前端安全

本文概述了浏览器的同源策略限制、防止CSRF的措施(如验证Referer和Token)、XSS攻击的分类与防护手段,以及CORS如何扩展AJAX的跨域能力。还介绍了重放攻击和点击劫持的防范技巧,以及加密算法的基础概念。
摘要由CSDN通过智能技术生成

1. 同源策略

URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。

浏览器的同源策略,限制了来自不同源的document或脚本,对当前document读取或设置某些属性。从一个域上加载的脚本不允许访问另外一个域的文档属性。

如果没有同源限制存在,浏览器中cookie等其他数据可以任意读取,不同域下DOM可以任意操作,ajax可以任意请求。如果浏览了恶意网站那么就会泄漏这些隐私数据

在浏览器中,<script><img><iframe><link>等标签都可以加载跨域资源,而不受同源限制。

2. CSRF

CSRF(Cross Site Request Forgery)跨站请求伪造是攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

CSRF 利用的是网站对用户网页浏览器的信任。

一个典型的CSRF攻击有着如下的流程:

  • 受害者登录a.com,并保留了登录凭证(Cookie)

  • 攻击者引诱受害者访问了b.com。

  • b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。

  • a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。

  • a.com以受害者的名义执行了act=xx。

  • 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。

在这里插入图片描述

常见的攻击类型

  • GET类型的CSRF
  • POST类型的CSRF
  • 链接类型的CSRF

防护措施

  • 验证Referer
    根据 HTTP 协议,在 HTTP 头中有一个字段叫Referer,它记录了该 HTTP 请求的来源地址。通过验证Referer,可以检查请求是否来自合法的"源"。

  • 验证Token
    服务端随机生成token,保存在服务端session中,同时保存到客户端中,客户端发送请求时,把token带到HTTP请求头或参数中,服务端接收到请求,验证请求中的token与session中的是否一致。如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

  • 禁止第三方网站携带本网站的cookie信息

    设置same-site属性,same-site属性有两个值,Strict(所有的第三方请求都不能携带本网站的cookie)和Lax(链接可以,但是form表单提交和ajax请求不行

  • 验证码
    通过增加网站A的验证手段,例如增加图形验证码或短信验证码等等,只有通过验证的请求才算合法。但是这种方案拥有两个局限性,一个是增加开发成本,另外一个是降低用户体验。

注:CSRF(通常)发生在第三方域名,不能获取到Cookie等信息,只是使用。

3. XSS

XSS攻击全称跨站脚本攻击(Cross-Site Scripting),为区别CSS,安全领域叫做XSS。

攻击者通过在目标网站上注入恶意脚本并运行,获取用户敏感信息如 Cookie、SessionID等,影响网站与用户数据安全。

XSS 利用的是用户对指定网站的信任。

XSS攻击分类

在这里插入图片描述

反射型

反射型XSS只是把用户输入的数据“反射”给浏览器,攻击者往往需要诱使用户操作一个恶意链接,才能攻击成功。

存储型

恶意代码保存到目标网站服务器中,这种攻击具有较强稳定性和持久性,比较常见场景是在博客,论坛、OA、CRM等社交网站上。

攻击流程:

  1. 攻击者提交一条包含XSS代码的留言或其他数据到数据库
  2. 当目标用户查询时,XSS的内容会从服务器解析之后加载出来
  3. 浏览器将恶意代码当作正常脚本解析执行,可以执行浏览器所具有权限下的命令

DOM

通过恶意脚本修改页面的DOM结构,是纯粹发生在客户端的攻击。

存储型XSS的恶意代码存在数据库里,反射型XSS的恶意代码存在URL里。

DOM型XSS攻击中,取出和执行恶意代码由浏览器端完成,属于前端JS自身的安全漏洞,而其他两种XSS都属于服务端的安全漏洞

防护措施

  • 开启浏览器自带防御机制

  • XSS攻击代码过滤(js下的js-xss,JAVA下的XSS HTMLFilter)

  • 输出检查

    利用转义库对 HTML 模板各处节点进行充分的转义。

  • 输入内容长度限制

    对输入的内容限定合理长度,可以增加XSS攻击的难度

  • 使用HttpOnly
    通过设置HttpOnly,浏览器可以禁止页面的JavaScript访问带有HttpOnly属性的Cookie。它的目的并非是为了对抗XSS,而是对抗XSS之后的Cookie劫持攻击。

    HttpOnly是在Set-Cookie的时候进行标记的

Set-Cookie: <name>=<value>[; <Max-Age>=<age>] [; expires=<date>][; domain=<domain_name>] [; path=<some_path>][; secure][; HttpOnly]
  • 开启CSP网页安全政策

    通过HTTP头信息的Content-Security-Policy字段

    在网页中设置<meta>标签

    <meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
    

注:不论是 Cookie 还是 token 都无法XSS。

4. CORS

CORS(Cross-origin resource sharing)是一个W3C标准,全称是"跨域资源共享"。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

简单请求

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.com
# 是否允许发送Cookie
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

非简单请求

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

# 预检"请求的HTTP头信息。
# 这个请求是用来询问的
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
# CORS请求会用到哪些HTTP方法
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
# 确认允许跨源请求,就可以以下回应
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
# "预检"请求之后,浏览器的正常CORS请求。
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
# 响应
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

注:CORS与JSONP的使用目的相同,但是比JSONP更强大。

JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

5. 重放攻击 Replay Attacks

重放攻击是攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程。

主机A给主机B发送的报文被攻击者C截获了,然后C伪装成A给B发送其截获来的报文,而B会误以为C就是A,就把回应报文发送给了C。虽然A是加密的,但C根本不用破译。

防范措施

防止重放攻击的方法是使用不重数。需保存某个很短时间段内的所有随机数,而且时间戳的同步也不需要太精确;使用挑战一应答机制和一次性口令机制。

  • 加随机数

    认证双方不需要时间同步,双方记住使用过的随机数,如发现报文中有以前使用过的随机数,就认为是重放攻击。需要额外保存使用过的随机token值,则需要保存和查询开销

  • 加流水号

    双方在报文中添加一个逐步递增的整数,则只要收到一个不连续的流水号报文(太大或者太小)就认为有重放威胁

  • 加时间戳

    不用额外保存其他信息。缺点是认证双方需要准确的时间同步,同步越好,受攻击的可能性就越小。

6. 重复提交请

以下情况都会导致表单重复提交,造成数据重复,增加服务器负载,严重甚至会造成服务器宕机。

  1. 由于用户误操作,多次点击表单提交按钮。
  2. 由于网速等原因造成页面卡顿,用户重复刷新提交页面。
  3. 黑客或恶意用户使用postman等工具重复恶意提交表单(攻击网站)。

防范措施

  • 通过JavaScript屏蔽提交按钮(不推荐)

    js代码很容易被绕过。比如用户通过刷新页面方式,或使用postman等工具绕过前段页面仍能重复提交表单。

  • 数据库增加约束

    约束能有效避免数据库重复插入相同数据。但无法阻止恶意用户重复提交表单(攻击网站),服务器大量执行sql插入语句,增加服务器和数据库负荷。

  • session防止表单重复提交

    服务器返回表单页面时,会先生成一个subToken保存于session,并把该subToen传给表单页面。首次提交表单时session的subToken与表单携带的subToken一致走正常流程,删除subToken,当再次提交表单时由于session的subToken为空则不通过。

  • Aop自定义实现

    实现原理:

    1. 自定义防止重复提交标记(@AvoidRepeatableCommit)。
    2. 对需要防止重复提交的Congtroller里的mapping方法加上该注解。
    3. 新增Aspect切入点,为@AvoidRepeatableCommit加入切入点。
    4. 每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
    5. 重复提交时Aspect会判断当前redis是否有该key,若有则拦截。
    import java.lang.annotation.*;
    
    /**
    * 自定义标签
    */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AvoidRepeatableCommit {
        long timeout()  default 30000 ;
    }
    
    @Aspect
    @Component
    public class AvoidRepeatableCommitAspect {
    
        @Autowired
        private RedisTemplate redisTemplate;
        @Around("@annotation(com.xwolf.boot.annotation.AvoidRepeatableCommit)")
        public Object around(ProceedingJoinPoint point) throws Throwable {
    
            HttpServletRequest request  = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
            String ip = IPUtil.getIP(request);
            //获取注解
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            //目标类、方法
            String className = method.getDeclaringClass().getName();
            String name = method.getName();
            String ipKey = String.format("%s#%s",className,name);
            int hashCode = Math.abs(ipKey.hashCode());
            String key = String.format("%s_%d",ip,hashCode);
            log.info("ipKey={},hashCode={},key={}",ipKey,hashCode,key);
            AvoidRepeatableCommit avoidRepeatableCommit =  method.getAnnotation(AvoidRepeatableCommit.class);
            long timeout = avoidRepeatableCommit.timeout();
            if (timeout < 0){
                //过期时间5分钟
                timeout = 60*5;
            }
            String value = (String) redisTemplate.opsForValue().get(key);
            if (StringUtils.isNotBlank(value)){
                return "请勿重复提交";
            }
            redisTemplate.opsForValue().set(key, UUIDUtil.uuid(),timeout,TimeUnit.MILLISECONDS);
            //执行方法
            Object object = point.proceed();
            return object;
        }
    
    }
    

7. 点击劫持

第三方网站通过iframe内嵌某一个网站,并且将iframe设置为透明不可见,将其覆盖在其他经过伪装的DOM上,伪装的可点击DOM(按钮等)与实际内嵌网站的可点击DOM位置相同,当用户点击伪装的DOM时,实际上点击的是iframe中内嵌的网页的DOM从而触发请求操作

特点:用户自己做了点击操作;用户毫不知情

防护措施

  • Javascript禁止内嵌

    <script>
    if (top.location != window.location) {
        //如果不相等,说明使用了iframe,可进行相关的操作
    }
    </script>
    

    但是这种方式并不是万能的,因为iframe标签中的属性sandbox属性是可以禁用内嵌网页的脚本的:

    <iframe sandbox='allow-forms' src='...'></iframe>
    
  • 设置http响应头 X-Frame-Options:有三个值 DENY(禁止内嵌) SAMEORIGIN(只允许同域名页面内嵌) ALLOW-FROM(指定可以内嵌的地址)

    能在所有的web服务器端预设好X-Frame-Options字段值是最理想的状态

8.加密算法

加密技术是对信息进行编码和解码的技术。编码是把可读信息(又称明文)译成代码形式(又称密文),其逆过程就是解码。加密技术的要点是加密算法,加密算法可以分为三类:

对称加密,如AESDES3DES

将明文分成N个组,然后使用密钥对各个组进行加密,形成各自的密文,最后把所有的分组密文进行合并,形成最终的密文。

优势:算法公开、计算量小、加密速度快、加密效率高

缺陷:双方都使用同样密钥,安全性得不到保证

非对称加密,如RSA、DSA

同时生成两把密钥:私钥和公钥,私钥隐秘保存,公钥可以下发给信任客户端。

私钥加密,持有私钥、公钥才可以解密;公钥加密,持有私钥才可以解密;

优点:安全,难以破解

缺点:算法比较耗时

不可逆加密 MD5、SHA1、HMAC

加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,无法根据密文推算出明文。

在这里插入图片描述

参考

前端安全系列之二:如何防止CSRF攻击?

浅说 XSS 和 CSRF

浅谈前端安全

防止表单重复提交的4种方法

跨域资源共享 CORS 详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值