安全问题:SQL 注入、XSS、CSFR攻击

365 阅读7分钟

安全问题的来源主要是客户端对服务器的恶意访问

  • 因为http是无状态协议,但是实际应用使用过程中有记录用户行为的需求,所以出现了一些保存用户行为的数据结构,相关信息涉及用户隐私和权限。所以这部分信息的安全问题很关键。

cookie:浏览器为特定网页或者网站保存的少量命名数据,作为http协议的扩展实现,默认自动在浏览器和服务器之间传输。 关于cookie机制,推荐查看另一篇博客

SQL 注入

某网站登录验证的查询句:

strSQL = "SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"+ passWord +"');"

而恶意用户输入的参数为:

userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";

直接做拼接:

strSQL = "SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');"
// 相当于
strSQL = "SELECT * FROM users;"

参数化查询来避免直接将参数与查询句拼接,并进行适当的输入检查、插入转义字符、严格设定程序权限,就能够有效避免 SQL 注入了

XSS

Cross-site scripting 通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序

攻击

XSS 通过修改 HTML 节点或者执行 JS 代码来攻击网站。 例如:

  • 通过 URL
用户输入网址:
http://www.domain.com?name=<script>alert(1)</script>
该网站已经做了转译处理:
https://www.domain.com/?name=%3Cscript%3Ealert(1)%3C/script%3E
如果没有经过转译:
将 HTML 改为 `<div><script>alert(1)</script></div>`,可以注入盗用cookie的代码
  • 通过各个元素的background-image 属性或者元素上的各种事件回调来实现,例如:解决跨域的jsonp方法
  • 一种有趣的解决方式,即 API 的响应内容开头为 for ( ; ; )利用script 元素引入的 JavaScript 会立即执行的特性,把攻击者的网站卡死在循环里

SVG

SVG中可以写入任意HTML,还可以加上onload事件,如果把SVG当成普通图片处理,直接作为网站内容使用,如果遇到恶意用户的话,后果不堪设想。所以在上线上传图片功能时,务必要把SVG过滤掉!

innerHTML

HTML5为所有元素提供了一个innerHTML属性,可读写

  • 浏览器会将属性值解析为相应的DOM树
  • HTML解析器在浏览器中是底层代码比JavaScript方法快很多,同时底层意味着替换元素上的关联事件处理程序和JavaScript对象需要手动删除。

outerHTML

== innerHTML定义的DOM树+自身元素

innerText与outerHTML: innerText:后代的所有文本 删除后代DOM树,赋值文本内容

Content-Type: application/javascript

部分浏览器会将当作javascript代码直接解析 严格定义Content-Type application/json 针对jsonp需要严格过滤callback后的参数并且限制长度

防御

  • 两条原则:过滤输入和转义输出

  • .innerHTML、.outerHTML、document.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent、.setAttribute() 等。

  • 如果用 Vue/React 技术栈,不使用 v-html/dangerouslySetInnerHTML 功能,在前端 render 阶段避免 innerHTML、outerHTML 的 XSS 隐患。

  • 把应用的不可信内容显示在iframe中,并将iframe的sandbox属性设置为禁用脚本和其他能力

  • 防止cookie信息被盗:阻止不好的后果 cookie中可以设置HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性,即便是这样,也不要将重要信息存入cookie。

response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")

CSP

Content Security Policy 入门教程 - 阮一峰的网络日志 (ruanyifeng.com) 白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行

开启 CSP的方法:配置选项

  • 通过 HTTP Header 中的 Content-Security-Policy
  • 通过网页的<meta>标签
Content-Security-Policy: default-src ‘self’
只允许加载本站资源 default-src ‘self’
只允许加载 HTTPS 协议图片 img-src https://*
允许加载任何来源框架 child-src 'none'

xss与csrf区别

  • 通常 CSRF 是由 XSS 实现的,CSRF 时常也被称为 XSRF(CSRF 实现的方式还可以是直接通过命令行发起请求等)。
  • 本质上,XSS 是代码注入问题,CSRF 是 HTTP 问题。XSS 是内容没有过滤导致浏览器将攻击者的输入当代码执行。CSRF 则是因为浏览器在发送 HTTP 请求时候自动带上 cookie

CSFR攻击

CSRF(Cross-site request forgery)跨站请求伪造

  1. 受害者登录a.com,并保留了登录凭证(Cookie)。
  2. 攻击者引诱受害者访问了b.com。
  3. b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。
  4. a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
  5. a.com以受害者的名义执行了act=xx。
  6. 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。
  • 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”-利用了cookie会自动添加到headers的特点
  • CSRF通常是跨域的,因为外域通常更容易被攻击者掌控去发起请求处理事件、获取数据。所以本域下需注意不要出现容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,更加危险

举例

假设网站中有一个通过 Get 请求提交用户评论的接口【攻击目标】,那么攻击者就可以在钓鱼网站中加入一个图片,图片的地址就是评论接口

<img src="http://www.domain.com/xxx?comment='attack'" />

如果接口是 Post 提交的,就相对麻烦点,需要用表单来提交接口

<form action="http://www.domain.com/xxx" id="CSRF" method="post">
  <input name="comment" value="attack" type="hidden" />
</form>

解决方法

  • 不让第三方网站访问到用户Cookie

  • 阻止第三方网站请求接口,同源检测

  • 双重Cookie验证

  • 请求时附带验证信息 CSRF Token:在 Cookie 及请求发送的数据中都加上 csrf token,并检查值是否相同,如果请求来源是自己的网站验证就会通过;反之,由于外部网站无法在代码中得到其他网站的 Cookie,因此无法在请求中带上 csrf token

  • 验证referer 在 HTTP 头中有一个字段, Referer记录HTTP 请求的来源地址。 服务器可以验证客户端的请求来源,如果本网站请求的则响应,否则不响应。

存在安全隐患

  1. 一些浏览器, IE6、 FF2有一些方法可以篡改 Referer 值
  2. 用户自己可以设置浏览器使其在发送请求时不再提供 Referer
  • cookie的SameSite属性 Chrome 51 开始,浏览器的 Cookie 新增,控制cookie的携带机制,用来防止 CSRF 攻击和用户追踪。

SameSite属性值:

  1. Strict:完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
  2. Lax:大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外
  3. None
Set-Cookie: flavor=choco; SameSite=None; Secure

JSON 劫持

json劫持攻击又为”JSON Hi jacking”,攻击过程类似于csrf,相比csrf只管发送http请求,json-hi-jack目的是获取敏感数据。

获得使用者权限,并调用获取资料的 API,再加上改写原生的 JavaScript 对象,比如覆盖数组的构造函数,从而劫持请求返回的JSON数组数据,转而将数据发送回给恶意攻击者

Object.prototype.__defineSetter__ 可以修改原生对象所造成的问题,在 ES4 中被修复,JSON 劫持也因此有所削弱,但是从 ES6 开始又添加了 Proxy,使 JSON 劫持又再次成为可能
Object.setPrototypeOf( 
     __proto__, 
     new Proxy(__proto__, { 
        hasfunction(target, name) { 
          alert( 
            name.replace(/./gfunction(c) { 
              c = c.charCodeAt(0) 
              return String.fromCharCode(c >> 8, c & 0xff) 
           }) 
          ) 
        } 
     }) 
);

举个攻击实例

是一种利用 Cookie 及 Session 认证机制进行攻击的手段

银行的转账网址:

www.examplebank.com/withdraw?ac…

恶意用户如果在网站中注入

<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">

当不知情的用户浏览到攻击者的网站时,<img / > 会自动发出这个请求,如果登录银行的 Session 尚未过期,那么这个请求很可能就会被银行接受,最后会在用户本人不知情的情况下“被”转帐。

这种攻击方式可以与前面所说的 XSS 是相辅相成,例如在没有防范 XSS 的论坛网站中植入 < img/>,那么其 src 属性就应该是获取敏感信息的 API URL。