前端中的安全攻防

1. sql 脚本注入

所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。攻击者通过在应用程序预先定义好的SQL语句结尾加上额外的SQL语句元素,欺骗数据库服务器执行非授权的查询,篡改命令。

1. URL地址防注入

1
2
3
4
5
6
7
8
9
//过滤URL非法SQL字符
var sUrl=location.search.toLowerCase();
var sQuery=sUrl.substring(sUrl.indexOf("=")+1);
re=/select|update|delete|truncate|join|union|exec|insert|drop|count|'|"|;|>|<|%/i;
if(re.test(sQuery))
{
alert("请勿输入非法字符");
location.href=sUrl.replace(sQuery,"");
}

2. 输入文本框防注入

1
2
3
4
5
6
7
8
9
10
11
12
//防止SQL注入
function AntiSqlValid(oField )
{
re= /select|update|delete|exec|count|'|"|=|;|>|<|%/i;
if ( re.test(oField.value) )
{
alert("请您不要在参数中输入特殊字符和SQL关键字!");
oField.value = ";
oField.className="errInfo";
oField.focus();
return false;
}

3. 参数化查询

所谓的参数化查询是指在设计与数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数来给值。

1
2
3
4
5
SELECT * FROM myTable WHERE myID = @myID

INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2, @c3, @c4)

INSERT INTO myTable (c1, c2, c3, c4) VALUES(?,?,?,?)

2. xss 跨站脚本攻击

XSS 全称(Cross Site Scripting) 跨站脚本攻击,是Web程序中最常见的漏洞。指攻击者在网页中嵌入客户端脚本(例如JavaScript), 当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的. 比如获取用户的Cookie,导航到恶意网站,携带木马等。

  • 反射型XSS

又称非持久型XSS。之所以称为反射型XSS,则是因为这种攻击方式的注入代码是从目标服务器通过错误信息、搜索结果等等方式“反射”回来的。而称为非持久型XSS,则是因为这种攻击方式具有一次性。攻击者通过电子邮件等方式将包含注入脚本的恶意链接发送给受害者,当受害者点击该链接时,注入脚本被传输到目标服务器上,然后服务器将注入脚本“反射”到受害者的浏览器上,从而在该浏览器上执行了这段脚本。

  • 存储型XSS

存储型XSS,又称持久型XSS,他和反射型XSS最大的不同就是,攻击脚本将被永久地存放在目标服务器的数据库和文件中。这种攻击多见于论坛,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入到帖子的内容之中。随着帖子被论坛服务器存储下来,恶意脚本也永久地被存放在论坛服务器的后端存储器中。当其它用户浏览这个被注入了恶意脚本的帖子的时候,恶意脚本则会在他们的浏览器中得到执行,从而受到了攻击。

  • DOM 型 XSS

DOM型XSS纯靠前端执行,与服务端并不交互。攻击者构造出特殊的 URL,其中包含恶意代码,用户打开带有恶意代码的 URL,用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行,恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

XSS 攻击的目的:

  • 获取用户cookie
  • 钓鱼攻击(构建一个钓鱼页面,获得用户输入的账号密码)

预防 XSS 攻击方案:

1. 输入过滤

对于明确的输入类型,例如数字、URL、电话号码、邮件地址等等内容,只允许输入规定的字符,其他特殊的字符都过滤掉。当然攻击者完全可以通过接口直接发数据给服务端,所以服务端在存储到数据库之前最后也进行特殊字符的检测过滤。

1
2
3
4
5
6
7
8
9
10
11
htmlEncodeByRegExp:function (str){  
var s = "";
if(str.length == 0) return "";
s = str.replace(/&/g,"&amp;");
s = s.replace(/</g,"&lt;");
s = s.replace(/>/g,"&gt;");
s = s.replace(/ /g,"&nbsp;");
s = s.replace(/\'/g,"&#39;");
s = s.replace(/\"/g,"&quot;");
return s;
}

2. 设置cookie只读

HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。

3. 纯前端渲染

  1. 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
  2. 然后浏览器执行 HTML 中的 JavaScript。
  3. JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。

在纯前端渲染中,我们会明确的告诉浏览器:下面要设置的内容是文本(.innerText),还是属性(.setAttribute),还是样式(.style)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。

4. 谨慎使用innerHtml

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

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

5. 验证码

验证码:防止脚本冒充用户提交危险操作。

3. CSRF 跨站脚本伪造

要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1. 登录受信任网站A,并在本地生成Cookie。
  2. 在不登出A的情况下,访问危险网站B。

CSRF的防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。

1. 表单添加hash值

在表单里增加Hash值,然后在服务器端进行Hash值验证,以认证这确实是用户发送的请求。

2. 验证码

每次的用户提交都需要用户在表单中填写一个图片上的随机字符串

3. token

CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对。

4. 验证HTTP Referer字段

根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如上文中用户User想要在网站WebA中进行转账操作,那么用户User必须先登录WabA,然后再通过点击页面上的按钮出发转账事件。这时该转帐请求的 Referer 值就会是转账按钮所在的页面的URL,而如果黑客要对银行网站实施 CSRF攻击,他只能在他自己的网站构造请求,当用户User通过黑客的网站发送请求到WebA时,该请求的 Referer 是指向黑客自己的网站。

5. 只使用json api

使用JavaScript发起AJAX请求是限制跨域的,并不能通过简单的form表单来发送JSON,所以,通过只接收JSON可以很大可能避免CSRF攻击。