总结和概括一下常见的Web安全注意点
XSS攻击
XSS(Cross Site Script)攻击,是攻击者想Web页面提交恶意脚本,当用户浏览页面的时候就会触发脚本。
攻击思路
- 盗取Cookie,模拟用户登录。用
document.cookie
获取cookie然后发送给某个后台服务器 - 弹出”Flash插件已过期”的提示,欺骗用户去钓鱼页下载被种下木马的插件
检测方式
一般的检测方式是检测弹窗,看能否执行alert(1)
- 对提交后展示的文本,输入
<script>alert(1)</script>
- 提交插入图片的连接,输入
javascript:alert(1)
,图片元素会被渲染成<img src="javascript:alert(1)">
预防方式
- 后端对
<>
使用<>
对输入内容转义,或者node用encodeURI
对文本转义 - 使用React可以避免XSS攻击,只有明确需要嵌入html代码的时候,使用
<span dangerouslySetInnerHTML={{"__html":data}}></span>
SQL注入
SQL注入是通过构造输入,改变服务端的SQL执行逻辑。例一条登录判断的SQL:select * from user where username = '" + username + "' and password = '" + password + "'"
。对于任何用户名,构造以下输入作为密码:
' or '1'='1
' or '1'='1' --
' or '1'='1' /*
实际上最终执行的SQL是select * from user where username = 'xxx' and password = '' or '1'='1'
,这条一定可以查找到用户实现登录。
攻击思路
- 构造多条语句:
' or '1'='1'; DROP TABLE user; --
,删库。也可用来修改用户密码,创建新用户 - UDF反弹Shell,对服务器提权
检测方式
单引号检测,一般老式php,asp项目存在SQL注入点的时候遇到单引号输入会报错
预防方式
使用SQL的预编译功能
JDBC的PreparedStatment继承自Statement,Statement执行SQL语句(包含参数)会直接发给DBMS,编译后直接执行;PreparedStatement执行SQL先将用?作为占位符的SQL语句模板发给DBMS先编译,之后直接运行编译后的SQL语句,参数在执行阶段传入。
<select id="selectPerson" parameterType="int" resultType="hashmap"> |
Mybatis中有两种参数传递的方式:#{}
、是先传递参数,然后再执行编译,再执行语句。为了避免被SQL注入,应采用#
传参。
CSRF攻击
CSRF(cross-site request forgery),跨站请求伪造。攻击者可以通过冒用你的身份执行某些请求。
完成一次CSRF攻击,被攻击人必须:
- 登录受信任网站A,并在本地生成Cookie
- 在不登出A(Cookie没有过期)的情况下,访问危险网站B。
攻击案例
站点A的某个接口以GET请求完成银行转账操作:
GET https://somebank.com/transfer?bankid=114514&money=1919810
。被害人登录A后继续访问了B,B页面中有这样一串代码:<img src="https://somebank.com/transfer?bankid=114514&money=1919810">
浏览器会带上用”somebank.com”的Cookie执行这一请求,使得用户给卡号为114514的卡汇入了1919810元。
上个案例中A使用GET方法设计请求,违反了HTTP规范,于是他们改用POST。对于一些老的PHP实现的后台站点,如果获取参数采用的
$_REQUEST["bankdid"]
这种方式,不区分GET和POST,照样能获得参数,所以POST还是没有起到作用。
假设后台实现区分了POST,危险站点B依然可以构造一个POST请求:<html>
<head>
<script type="text/javascript">
function steal() {
iframe = document.frames["steal"];
iframe.document.submit("transfer");
}
</script>
</head>
<body onload="steal()" src="https://somebank.com">
<iframe name="steal" display="none">
<form method="POST" name="transfer" action="https://somebank.com/transfer">
<input type="hidden" name="bankid" value="114514">
<input type="hidden" name="money" value="1919810">
</form>
</iframe>
</body>
</html>
即使A站点不允许跨域,该处也可以用iframe构造一个同域的请求。
预防方式
- 尽可能使用POST执行需要高安全性保障的接口
- 将页面HTTP返回Header加上
X-Frame-Options: DENY
。
X-Frame-Options
头部选项中,DENY
是拒绝非同源页面引用该页面;SAMEORIGIN
是允许被同源页面引用,ALLOW-FROM uri
是允许被特定页面引用。
- 设置页面HTTP返回头
Content-Security-Policy: script-src
。将设置外链js只能从本域名引用。 - 对于支付等特别敏感的接口,强制使用验证码
- 由于CSRF攻击中假设A站点是可信的,不存在A站点还有XSS漏洞,攻击者无法拿到A站点的Cookie。所以基于这一判断,可以对Cookie Hashing,让表单中包含一个
hash(cookie)
的token
字段。服务器端接受表单请求的时候需要判断hash(cookie) == token
才能继续执行,由于攻击者无法直接拿到Cookie,而且就算使用中间人攻击拿到了token
也无法反推出cookie
,这个方案可以彻底解决CSRF攻击。如果A页面也含有XSS漏洞,可以让攻击者拿到Cookie,可以让A页面的Cookie或者SESSION每次都变动,每次请求生成一个随机字段,并将改字段的hash渲染在form上,这样每次请求页面都会获取一个新的token,让攻击者几乎没有可能有时间伪造请求。
参考资料: