1 常见的 Web 攻击
1.1 CSRF攻击
CSRF:Cross Site Request Forgery(跨站点请求伪造)。利用信任用户已经获取的注册凭证,绕过后台用户验证,向被攻击网站发送未被用户授权的跨站请求以对被攻击网站执行某项操作的一种恶意攻击方式。
CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
1.1.1 CSRF如何防护
- 安全框架:例如Spring Security(csrf-token 机制)。
- 验证码校验:敏感操作添加验证码,涉及金钱交易的可以采用此方法。
- referer字段识别:在HTTP Header中有一个字段Referer,它记录了HTTP请求的来源地址。如果Referer是其他网站,就有可能是CSRF攻击,则拒绝该请求。
- sign签名机制:用不可逆转的加密算法加密参数,服务器端用同样的方法加密,对比sign是否一样。有效防止内容篡改。
1.2 XSS 攻击
XSS 即(Cross Site Scripting)中文名称为:跨站脚本攻击。XSS的重点不在于跨站点,而在于脚本的执行。
恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。
1.2.1 XSS 攻击分类
- 反射型Xss:反射性xss一般指攻击者通过特定的方式来诱惑受害者去访问一个包含恶意代码的URL。当受害者点击恶意链接url的时候,恶意代码会直接在受害者的主机上的浏览器执行。
- 存储型Xss:主要是将恶意代码上传或存储到服务器中,下次只要受害者浏览包含此恶意代码的页面就会执行恶意代码。
- DOM Xss:我们客户端的js可以对页面dom节点进行动态的操作,比如插入、修改页面的内容。比如说客户端从URL中提取数据并且在本地执行、如果用户在客户端输入的数据包含了恶意的js脚本的话,但是这些脚本又没有做任何过滤处理的话,那么我们的应用程序就有可能受到DOM-based Xss的攻击。
1.2.2 XSS 防护
- 输入过滤:<script 、<img、<a 等标签进行过滤。
- 纯前端渲染:静态 HTML,Ajax 加载业务数据,调用 DOM API 更新到页面上。
- 转义HTML:把 & < > " ’ / 这几个字符转义掉。转义库为 org.owasp.encoder。
- 内容长度控制:数字、URL、电话号码、邮件地址等内容控制长度。
- Cookie的安全设置:禁止 JavaScript 读取某些敏感 Cookie。
- 安全验证:关键业务,如支付需要验证码验证。
- 开启CSP(Content Security Policy)网页安全政策:控制哪些域名下的静态资源可以被页面加载,哪些不能被加载。
- 避免内联事件:尽量不要使用 onLoad=“onload(‘{{data}}’)”、onClick=“go(‘{{action}}’)” 这种拼接内联事件的写法。在 JavaScript 中通过 .addEventlistener() 事件绑定会更安全。
1.3 DOS 攻击
通过各种手段消耗网络带宽和系统资源,或者攻击系统缺陷,使正常系统的正常服务陷于瘫痪状态,不能对正常用户进行服务,从而实现拒绝正常的用户访问服务。
1.3.1 防护
利用DDoS防御产品的检测技术和清洗技术,检测技术就是检测网站是否正在遭受DDoS攻击,而清洗技术就是清洗掉异常流量。例如:
H3C IPS(Intrusion Prevention System)防护:检查经过的进出流量中每个比特并过滤掉不想要的流量,在线保护与之连接的网络和主机。
1.4 SQL 注入
击者成功的向服务器提交恶意的SQL查询代码,程序在接收后错误的将攻击者的输入作为查询语句的一部分执行,导致原始的查询逻辑被改变,额外的执行了攻击者精心构造的恶意代码。
1.4.1 SQL 注入防护
- 使用预编译语句(PreparedStatement)
- 对进入数据库的特殊字符(’"尖括号&*;等)进行转义处理,或编码转换。
- 使用Mybatis框架时,使用#{},防止sql注入
2 越权访问漏洞防护
越权访问(BrokenAccessControl,简称BAC)是Web应用程序中一种常见的漏洞,分为垂直越权访问和水平越权访问。
- 垂直越权:是指不同用户级别之间的越权,如普通用户执行管理员用户的权限。
- 水平越权:是指相同级别用户之间的越权操作。
2.1 权限校验
配置FILTER拦截器,对请求所有URL进行拦截,对于需要进行授权的URL进行权限校验,防止用户越权访问系统资源。
- 登录验证
- 菜单(功能)权限验证
- 授权节点(数据范围)权限验证
- 操作类型(完全控制,可编辑,可删除,只读)权限验证
3 文件上传攻击
前台仅使用JS对文件后缀做了过滤,这只能针对普通的用户,而恶意攻击者完全可以修改表单去掉JS校验。
项目中涉及上传下载未对文件大小以及类型进行验证,可能导致不良用户上传有害文件,危害服务器。
3.1 文件上传攻击解决方案
文件上传时在前台对文件后缀名进行验证,为避免通过特殊手段绕过了前端验证,在文件保存时再进行一次验证,即前后台同时验证的道理。
- 文件格式
- 文件大小
- 用户上传频率/用户每日上传个数限制
4 敏感信息泄露
- URL中包含敏感信息,暴露到地址栏中。
- 用户账号,手机号明文返回。
4.1 敏感信息防护
- 地址栏中不暴露敏感参数信息,通过local storage 或者 session storage存储和传递。
- api 接口返回,或者ajax请求,敏感数据经过加密算法进行加密,服务器端解码。
4.2 加密算法
不可逆算法:
- MD5算法:MD5算法是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护,MD5是以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成—个128位散列值。通常用于用户密码加密。
- SHA算法:SHA算法是一种消息摘要算法,SHA1主要适用于数字签名标准里面定义的数字签名算法。
非对称加密算法:
3. RSA算法:RSA算法是一种使用不同的加密密钥与解密密钥,是由已知加密密钥推导出解密密钥在计算上是不可行的密码体制,其原理是根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。RSA是目前最有影响力和最常用的公钥加密算法。
4. ECC算法:ECC算法是一种椭圆加密算法,可以通过较短的密钥达到相同的安全程度,常用于用于加解密、签名验签,也可以与DH结合使用,用于密钥磋商。
5. DSA算法:DSA算法是一种数字签名算法,是一种公开密钥算法,其不能用作加密,只用作数字签名,DSA算法使用公开密钥,可以为接受者验证数据的完整性和数据发送者的身份。
对称加密算法:
6. DES算法:DES算法是一种对称密码体制加密算法,为密码体制中的对称密码体制,其 明文按64位进行分组,密钥长64位,密钥是以56位参与DES运算,且第8、16、24、32、40、48、56、64位是校验位,分组后的明文组和56位的密钥按位替代或交换的方法形成密文组的加密方法。
7. DH算法:DH算法是一种密钥交换算法,可以让双方在完全没有对方任何预先信息的条件下通过不安全信道建立起一个密钥,且密钥可以在后续的通讯中作为对称密钥来加密通讯内容。
8. AES:这个标准用来替代原先的DES。
更多资料参考:https://www.jb51.net/article/214770.htm
5. 登录验证
由于http 协议是无状态的协议,那就意味着当有用户向系统使用账户名称和密码进行用户认证之后,下一次请求还要再一次用户认证才行。因为我们不能通过 http 协议知道是哪个用户发出的请求,所以如果要知道是哪个用户发出的请求,那就需要在服务器保存一份用户信息,然后在认证成功后返回 cookie 值传递给浏览器,那么用户在下一次请求时就可以带上 cookie 值,服务器就可以识别是哪个用户发送的请求,是否已认证,是否登录过期等等。
5.1 session认证
- 用户信息保存至 session。
- 在分布式部署应用中,会出现session不能共享的问题,很难扩展。
5.2 token认证
- 用户信息保存至 分布式 redis 中。
- 分布式部署应用共享redis,易于扩展。
- 占用redis空间,且每次请求都要查一下redis, 增加redis压力。
认证过程:
5.3 JWT认证
JWT (全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
5.3.1 JWT认证流程
- 用户使用账号、密码登录应用,登录的请求发送到 Authentication Server。
- Authentication Server 进行用户验证,然后创建 JWT 字符串返回给客户端。
- 客户端请求接口时,在请求头带上 JWT。
- Application Server 验证 JWT 合法性,如果合法则继续调用应用接口返回结果。
可以看出与token方式有一些不同的地方,就是不需要依赖 redis,用户信息存储在客户端。所以关键在于生成 JWT 和解析 JWT 这两个地方。
5.3.2 JWT的数据结构
- JWT 一般是这样一个字符串,分为Header、Payload、Signature三个部分,以 “.” 隔开:xxxxx.yyyyy.zzzzz
Header:
- JWT 第一部分是头部分,它是一个描述 JWT 元数据的 Json 对象,通常如下所示。
{
"alg": "HS256",
"typ": "JWT"
}
alg 属性表示签名使用的算法,默认为 HMAC SHA256(写为HS256),typ 属性表示令牌的类型,JWT 令牌统一写为JWT。
最后,使用 Base64 URL 算法将上述 JSON 对象转换为字符串保存。
Payload:
-
JWT 第二部分是 Payload,也是一个 Json 对象,除了包含需要传递的数据,还有七个默认的字段供选择。
- iss (issuer):签发人/发行人
- sub (subject):主题
- aud (audience):用户
- exp (expiration time):过期时间
- nbf (Not Before):生效时间,在此之前是无效的
- iat (Issued At):签发时间
- jti (JWT ID):用于标识该 JWT
需要注意的是,默认情况下 JWT 是未加密的,任何人都可以解读其内容,因此一些敏感信息不要存放于此,以防信息泄露。
Signature:
- JWT 第三部分是签名。
5.3.3 JWT校验方式
- 首先需要指定一个 secret,该 secret 仅仅保存在服务器中,保证不能让其他用户知道。这个部分需要 base64URL 加密后的 header 和 base64URL 加密后的 payload 使用 . 连接组成的字符串。
- 然后通过header 中声明的加密算法 进行加盐secret组合加密,然后就得出一个签名哈希,也就是Signature,且无法反向解密。
- 利用 JWT 前两段,用同一套哈希算法和同一个 secret 计算一个签名值,然后把计算出来的签名值和收到的 JWT 第三段比较,如果相同则认证通过。
5.3.4 JWT认证缺陷
- 安全性没法保证,所以 jwt 里不能存储敏感数据。因为 jwt 的 payload 并没有加密,只是用 Base64 编码而已。
- 无法中途废弃。因为一旦签发了一个 jwt,在到期之前始终都是有效的,如果用户信息发生更新了,只能等旧的 jwt 过期后重新签发新的 jwt。
- 续签问题。当签发的 jwt 保存在客户端,客户端一直在操作页面,按道理应该一直为客户端续长有效时间,否则当 jwt有效期到了就会导致用户需要重新登录。