先大概看下目前的常见前端安全问题
下面详细叙述之:
hello!<script type="type/javascript src="恶意网址"></script>
这样会通过前端代码来执行js脚本,如果这个恶意网址通过cookie获得了用户的私密信息,那么用户的信息就被盗了 htmlEncodeByRegExp:function (str){undefined var s = "";
if(str.length == 0) return "";
s = str.replace(/&/g,"&");
s = s.replace(/</g,"<");
s = s.replace(/>/g,">");
s = s.replace(/ /g," ");
s = s.replace(/\'/g,"'");
s = s.replace(/\"/g,""");
return s;undefined},其次在java后端还要进行安全防御,具体可以看一下这个http://blog.csdn.net/qq\\_34120041/article/details/76890092\_XSS\_初体验-存储型XSS DOM XSS 突变XSS 反射型XSS
CSRF攻击(cross site request forgery,跨站请求伪造)
CSRF,即(Cross-site request forgery), 中文名为跨站请求伪造。是一种挟持用户在当前已登录的Web应用程序上执行非本意的操作的一种攻击方式。\*\*CSRF攻击的本质在于利用用户的身份,执行非本意的操作\*\*。根据CSRF的全名,可以得出的结论是:CSRF的请求是\*\*跨域且伪造\*\*的。
csrf攻击形式:攻击者\*\*盗用用户的身份信息,并以用户的名义进行发送恶意的请求\*\*等,例如发邮件,盗取账号等非法手段例如:你登录网站,并在本地种下了cookie
如果在没退出该网站的时候 不小心访问了恶意网站,而且这个网站需要你发一些请求等
此时,你是携带cookie进行访问的,那么你的存在cookie里的信息就会被恶意网站捕捉到,那么你的信息就被盗用
攻击防御:
1、验证HTTP Referer字段
在HTTP头中有Referer字段,他记录该HTTP请求的来源地址,如果跳转的网站与来源地址相符,那就是合法的,如果不符则可能是csrf攻击,拒绝该请求
2、在请求地址中添加token并验证
这种的话在请求的时候加一个token,值可以是随机产生的一段数字,
token是存入数据库之后,后台返给客户端的,如果客户端再次登录的时候,
后台发现token没有,或者通过查询数据库不正确,那么就拒绝该请求
如果想防止一个账号避免在不同的机器上登录,那么我们就可以通过token来判断,
如果a机器登录后,我们就将用户的token从数据库清除,从新生成,
那么另外一台b机器在执行操作的时候,token就失效了,只能重新登录,这样就可以防止两台机器登同一账号
具体方案如下:
服务端在收到客户端请求时,生成一个随机数,在渲染页面时将随机数埋入页面(一般埋入form表单中),<input type="hidden" name="\\\\_csrf\\\\_token" value="xxxx">)`的形式。每次刷新页面后这个随机数都会改变,并在服务器中存储。 服务端设置Set-Cookie, 把该随机数作为cookie种入用户浏览器。 当用户发送GET或POST请求时带上\\_csrf\\_token参数(对于form表单直接提交即可) 后台在接受到请求后解析请求头中的cookie字段,获取\\_csrf\\_token的值,然后和用户请求提交的\\_csrf\\_token值做比较。如果相等则表示请求来源是合法的。
3、在HTTP头中自定义属性并验证
如果说通过每次请求的时候都得加token那么各个接口都得加很麻烦,
那么我们通过http的请求头来设置token例如:$.ajax({
url: '/v1/api',
dataType: 'json',
data: param,
type:'post',
headers: {'Accept':'application/json','Authorization':tokenValue}
success:function(res){
console.log(res)
}
})总结:因为CSRF攻击利用的是冲着浏览器分不清发起请求是不是真正的用户本人,所以防范的关键在于在请求中放入黑客所不能伪造的信息。从而防止黑客伪造一个完整的请求欺骗服务器。
unclekeith: 前端安全之CSRF攻击-get csrf,post csrf
所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
有一个Login画面,在这个Login画面上有两个文本框分别用来输入用户名和密码,当用户点了登录按钮的时候,会对输入的用户名和密码进行验证。验证的SQL语句如下:
select \\* from student where username=’输入的用户名’ and password=’输入的密码’
如果能够检索到数据,说明验证通过,否则验证不通过。如果用户在用户名文本框中输入 \\‘ or ‘1’ = ‘1’ or ‘1’ = ‘1,\\则验证的SQL语句变成:
select \* from student \\where username=” or ‘1’ = ‘1’ or ‘1’ = ‘1’ and password=”\\
如果用户在密码文本框中输入 1′ or ‘1’ = ‘1,则验证的SQL语句变成:
select \* from student where username=” and password=’1’ or ‘1’=’1′
以上两个\\SQL语句的where条件永远是成立的,所以验证永远是有效的。\\攻击防御:
1.URL地址防注入://过滤URL非法SQL字符//过滤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.输入文本框防注入:
/防止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();
returnfalse;
}
在需要防注入的输入文本框添加如下方法
`txtName.Attributes.``Add``(``"onblur"``,` `"AntiSqlValid(this)"``);//防止Sql脚本注入`
请求劫持现在主要分为两种,DNS劫持与HTTP劫持:
请求劫持唯一可行的预防方法就是尽量使用HTTPS协议访问。
HTTPS协议:https://juejin.im/entry/58d7635e5c497d0057fae036
什么是https,这里不再解释了,简单理解就是通过SSL(Secure Sockets Layer)层来加密http数据来进行安全传输。 那使用HTTPS是怎样进行加解密和安全数据传输的?
先看个有意思的问题:
A、B两个人分别在两个岛上,并且分别有一个箱子,一把锁,和打开这把锁的钥匙(A的钥匙打不开B手上的锁,B的钥匙也打不开A的锁)。此时A要跟B互通情报,此时需要借助C的船运输,C是一个不可靠的人,如果A直接把情报送给B或把情报放在箱子里给B,都可能会被C偷走;如果A把情报锁在箱子里,B没有打开A锁的钥匙无法获得情报内容。请问有什么办法可以尽可能快的让A和B互通情报。
这就是公钥和私钥的问题了,答案比较简单,也对应了公钥和私钥在https中的应用过程。
公钥(Public Key)与私钥(Private Key)是通过一种算法得到的一个密钥对(即一个公钥和一个私钥),公钥是密钥对中公开的部分,私钥则是非公开的部分。公钥通常用于加密会话密钥、验证数字签名,或加密可以用相应的私钥解密的数据。通过这种算法得到的密钥对能保证在世界范围内是唯一的。使用这个密钥对的时候,如果用其中一个密钥加密一段数据,必须用另一个密钥解密。比如用公钥加密数据就必须用私钥解密,如果用私钥加密也必须用公钥解密,否则解密将不会成功。---百度百科
整个通信过程如下图,以公钥加密方式为例:
1、客户端发送https请求,告诉服务器发将建立https连接
2、服务器将服务端生成的公钥返回给客户端,如果是第一次请求将告诉客户端需要验证链接
3、客户端接收到请求后'client finished'报文串通过获取到的服务器公钥加密发送给服务器,并将客户端生成的公钥也发送给服务器
4、服务器获取到加密的报文和客户端公钥,先使用服务器私钥解密报文,然后将报文通过客户端的公钥加密返回给客户端。
5、客户端通过私钥解密报文,判断是否为自己开始发送的报文串;如果正确,说明安全连接验证成功,将数据通过服务器公钥加密不断发送给服务器,服务器也不断解密获取报文,并通过客户端公钥加密返回给客户端验证。这样就建立了不断通信的连接。
以打开 https://github.com/ 的过程为例,请求通用头部如下
Request URL:https://github.com/ouvens\n Request Method:GET Status Code:200 OK (from cache) Remote Address:192.30.252.131:443 Response Headers
先看下请求头的字段
再截取部分返回头的字段
需要注意的upgrade-insecure-requests
https正常升级后chrome浏览器会出现下面的警告
考虑到这个问题,w3c在2015年4月份出了一个 Upgrade Insecure Requests 的草案,他的作用就是让浏览器自动升级请求。在服务器的响应头中加入:
header("Content-Security-Policy: upgrade-insecure-requests");
http层面上浏览器设置的安全性控制较多,这里列几个典型的来看看:
X-XSS-Protection:1; mode=block 0 – 关闭对浏览器的xss防护 1 – 开启xss防护 1; mode=block – 开启xss防护并通知浏览器阻止而不是过滤用户注入的脚本。 1; report=http://site.com/report – 这个只有chrome和webkit内核的浏览器支持,这种模式告诉浏览器当发现疑似xss攻击的时候就将这部分数据post到指定地址。 通常不正确的设置
application/ecmascript application/javascript application/x-javascript text/ecmascript text/javascript text/jscript text/x-javascript text/vbs text/vbscript
对于chrome,则支持下面的MIME 类型:
text/javascript text/ecmascript application/javascript application/ecmascript application/x-javascript text/javascript1.1 text/javascript1.2 text/javascript1.3 text/jscript text/live script
nosniff – 这个是唯一正确的设置,必须这样。max-age=31536000 – 告诉浏览器将域名缓存到STS list里面,时间是一年。 max-age=31536000; includeSubDomains – 告诉浏览器将域名缓存到STS list里面并且包含所有的子域名,时间是一年。 max-age=0 – 告诉浏览器移除在STS缓存里的域名,或者不保存此域名。 通常不正确的设置
判断一个主机是否在你的STS缓存中,chrome可以通过访问chrome://net-internals/#hsts,首先,通过域名请求选项来确认此域名是否在你的STS缓存中。然后,通过https访问这个网站,尝试再次请求返回的STS头,来决定是否添加正确。Content-Security-Policy:default-src *; base-uri 'self'; block-all-mixed-content; child-src 'self' render.githubusercontent.com; connect-src 'self' uploads.github.com status.github.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-src 'self' render.githubusercontent.com; img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com collector.githubapp.com *.gravatar.com *.wp.com *.githubusercontent.com; media-src 'none'; object-src assets-cdn.github.com; plugin-types application/x-shockwave-flash; script-src assets-cdn.github.com; style-src 'self' 'unsafe-inline' assets-cdn.github.com
X-Frame-Options: deny deny – 禁止所有的资源(本地或远程)试图通过frame来加载其他也支持X-Frame-Options 的资源。 sameorigion – 只允许遵守同源策略的资源(和站点同源)通过frame加载那些受保护的资源。 allow-from http://www.example.com – 允许指定的资源(必须带上协议http或者https)通过frame来加载受保护的资源。这个配置只在IE和firefox下面有效。其他浏览器则默认允许任何源的资源(在X-Frame-Options没设置的情况下)。
Access-Control-Allow-Origin : * *– 通配符允许任何远程资源来访问含有Access-Control-Allow-Origin 的内容。 http://www.example.com – 只允许特定站点才能访问(http://[host], 或者 https://[host])
公钥固定(Public Key Pinning)是指一个证书链中必须包含一个白名单中的公钥,也就是说只有被列入白名单的证书签发机构(CA)才能为某个域名*.example.com签发证书,而不是你的浏览器中所存储的任何 CA 都可以为之签发。可以理解为https的证书域名白名单。 Public-Key-Pins (PKP)的目的主要是允许网站经营者提供一个哈希过的公共密钥存储在用户的浏览器缓存里。跟Strict-Transport-Security功能相似的是,它能保护用户免遭中间人攻击。这个header可能包含多层的哈希运算,比如pin-sha256=base64(sha256(SPKI)),具体是先将 X.509 证书下的Subject Public Key Info (SPKI) 做sha256哈希运算,然后再做base64编码。然而,这些规定有可能更改,例如有人指出,在引号中封装哈希是无效的,而且在33版本的chrome中也不会保存pkp的哈希到缓存中。
这个header和 STS的作用很像,因为它规定了最大子域名的数量。此外,pkp还提供了一个Public-Key-Pins-Report-Only 头用来报告异常,但是不会强制阻塞证书信息。当然,这些chrome都是不支持的。
请求头说明参考:
https://www.veracode.com/blog/2014/03/guidelines-for-setting-security-headers/
总结下web的安全策略,主要介绍了
xss防范
csrf防范
sql注入防范
劫持与https
Content-Security-Policy(浏览器自动升级请求)
Strict-Transport-Security(配置浏览器和服务器之间安全的通信。它主要是用来防止中间人攻击,因为它强制所有的通信都走TLS)
Access-Control-Allow-Origin(这个header是决定哪些网站可以访问资源,通过定义一个通配符来决定是单一的网站还是所有网站可以访问我们的资源)
X-Frame-Options(这个header主要用来配置哪些网站可以通过frame来加载资源。它主要是用来防止UI redressing 补偿样式攻击)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。