Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

网络安全 #170

Open
coconilu opened this issue Jun 23, 2020 · 0 comments
Open

网络安全 #170

coconilu opened this issue Jun 23, 2020 · 0 comments

Comments

@coconilu
Copy link
Owner

coconilu commented Jun 23, 2020

安全问题的本质

安全问题的本质是信任的问题。数据从高等级的信任域流向低等级的信任域,是不需要经过安全检查的;数据从低等级的信任域流向高等级的信任域,则需要经过信任边界的安全检查。

比如火车站、飞机场都会有一个必要的程序:安全检查。机场会扫描乘客的行旅箱,检查乘客身上是否携带了打火机、可燃液体等危险物品,目的主要是过滤掉有害的、危险的东西。但是当我们从候机厅出来,是不需要做检查的。

安全方案的原则

1. Secure By Default 原则

“Secure By Default”原则,也可以归纳为白名单、黑名单的思想。

如果更多地使用白名单,那么系统就会变得更安全。因为黑名单需要防范很多未知的情况,而我们不一定能考虑周全。

比如,如果网站只提供Web服务,那么正确的做法是只允许网站服务器的80和443端口对外提供服务。又比如,在网站的生产环境服务器上,应该限制随意安装软件,而需要制定统一的软件版本规范,这个规范的制定,最好是选择白名单的思想来实现。

还有一个最小权限原则,要求系统只授予主体必要的权限,而不要过渡授权,这样能有效地减少系统、网络、应用、数据库出错的机会。

比如,在Linux系统中,一种良好的操作习惯就是使用普通账号登录,在执行需要root权限的操作时,再通过sudo命令完成。

2. 纵深防御原则

纵深防御(Defense in Depth)原则包含两层含义:

首先,要在各个不同层面、不同方面实施安全方案,避免出现疏漏,不同安全方案之间需要相互配合,构成一个整体;其次,要在正确的地方做正确的事情。

第一层含义不是同一个安全方案要做两遍或多边,而是要从不同的层面、不同的角度对系统做出整体的解决方案。

第二城含义,要把防御方案放到最适合的地方去解决。比如XSS防御技术里,不应该粗暴地把尖括号过滤掉,而是在瓶装HTML时处理特殊字符。

3. 数据与代码分离原则

这一原则广泛适用于各种由于“注入”而引发安全问题的场景。

在Web安全中,由“注入”引起的问题比比皆是,如SXX、SQL Injection、CRLF Injection、X-Path Injection等。此类问题均可以根据“数据与代码分离原则”设计出真正安全的解决方案,因为这个原则抓住了漏洞形成的本质原因。

4. 不可预测性原则

不可预测型(Unpredictable),能有效地对抗基于篡改、伪造的攻击,可以巧妙地用在一些敏感数据上。

比如在CSRF的防御技术中,通常会使用一个token来进行有效防御。这个token能成功防御CSRF,就是因为攻击者在实施CSRF攻击的过程中,是无法提前预知这个token值的,因此要求token足够复杂,不能被攻击者猜测到。

客户端脚本安全

1. 浏览器安全

浏览器作为一个客户端,是需要自带一些安全功能,这不仅能让它在浏览器市场中脱颖而出,还可以保证用户的部分信息安全。

同源策略

同源策略(Same Origin Policy)是第一种约定,它是浏览器最核心也是最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能会受到影响。可以说Web是构建在同源策略的基础之上的,浏览器知识针对同源策略的一种实现。

有关同源策略和跨域请求可以看我的另一篇文章:《同源策略与跨域请求》

浏览器沙箱

对于浏览器来说,采用Sandbox(沙箱)技术,可以让不受信任的网页代码、JavaScript代码运行在一个受到限制的环境中,从而保护本地桌面系统的安全。

现代浏览器的渲染引擎由Sandbox隔离,网页代码要与浏览器内核进程通信、与操作系统通信都需要通过IPC channel,在其中会进行一些安全检查。

恶意网址拦截

为了保护用户安全,浏览器厂商纷纷推出了各自的拦截恶意网址功能。大部分浏览器的拦截恶意网址的功能都是基于“黑名单”的。

现在的浏览器多是与专业的安全厂商展开合作,由安全厂商或机构提供恶意网址黑名单。

除了恶意网址黑名单拦截功能外,主流浏览器都开始支持EV SSL证书,以增强对安全网站的识别,这部分功能是基于“白名单”的。

其它安全策略

为了在安全领域获得竞争力,微软率先在IE8中推出了XSS Filter功能,用以对抗反射型XSS。

Firefox 4推出了Content Security Policy(CSP),CSP 的主要目标是减少和报告 XSS 攻击,通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。一个CSP兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和HTML的事件处理属性)。

CSP可以放在响应头里,也可以放在HTML的meta标签里。

X-Frame-Options,主要用于预防点击劫持。

Cookie的samesite属性,主要用于预防CSRF。

2. 跨站脚本攻击(XSS)

跨站脚本攻击,通常指黑客通过“HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。

XSS的关键是脚本而是跨站,它的类型有:

  1. 反射型XSS,把用户输入的数据“反射”给浏览器
  2. 存储型XSS,把用户输入的数据“存储”在服务器端
  3. DOM Based XSS,从效果上来说也是反射型XSS,通过JS修改页面的DOM节点形成的XSS

反射型XSS,一般要求攻击者诱使用户点击一个包含XSS代码的URL连接,服务器在渲染页面的时候会使用URL的部分数据,从而导致攻击发生。而存储型XSS,只需让用户查看一个正常的URL链接,但是网页里有XSS漏洞就会导致用户被攻击,比如论坛等有大量用户交互留言的场景。

XSS攻击场景:

  1. Cookie劫持,这可以通过cookie的httpOnly来防止攻击
  2. 构造Get和Post请求,如果cookie无法被劫持,也可以发起攻击,因为浏览器在发送同域名请求时会带上这个域名保存的cookie
  3. XSS 蠕虫攻击,一般来说,用户之间发生交互行为的页面,如果存在存储型XSS,则比较容易发起XSS 蠕虫攻击

正确预防XSS,需要针对特定的场景:

  1. 在HTML元素标签中填入用户数据,使用HTMLEncode
  2. 在HTML元素属性中填入用户数据,使用HTMLEncode
  3. 在<script>标签中填入用户数据,使用JavaScriptEncode
  4. 在事件中填入用户数据,使用JavaScriptEncode
  5. 在CSS中填入用户数据,在CSS和style、style attribute中形成XSS的方式非常多样化,尽可能禁止在CSS中填入用户数据
  6. 在地址中填入用户数据,使用URLEncode
  7. 富文本,使用白名单(避免使用黑名单)过滤标签,并且禁止自定义的CSS与style

开源社区有很多XSS解决方案,如果你使用的是JS,推荐下面npm上的这个库:xss,它可以按照白名单的方式过滤标签和属性,对于服务器渲染方案还是不错的。

鉴于现在大多数网站都使用react、vue之类的浏览器渲染方案,可以使用比较简单转义方案:

const htmlEscapeMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#39;",
"`": "&#96;",
};

3. 跨站点请求伪造(CSRF)

CSRF主要是依托浏览器发送cookie的策略进行的,不同的浏览器可能策略不太一样。当之前请求过一个域名并保存了cookie,那么下次再访问这个域名的资源就会带上保存的cookie。

CSRF攻击之所以可以成功,本质是因为重要操作的所有参数都是可以被攻击者猜测到的。

CSRF的防御策略:

  1. 验证码,强制用户与应用进行交互,只能作为防御CSRF的一种辅助手段,因为不能给所有的操作都加上验证码
  2. Referer Check,检查资源来源,也不能作为CSRF的主要手段,因为有些浏览器出于隐式保护的考虑,限制了Referer的发送
  3. Anti CSRF Token,token是随机生成的,用以校验本次请求的合法性,它会传递给客户端(作为表单的一部分),然后保留一份在session(或者作为cookie发送给客户端),当提交表单的时候会带上这个token,服务器会校验session中的token(或cookie中的token)和表单里的token是否一致

CSRF的Token仅仅用于对抗CSRF攻击,当网站还同时存在XSS漏洞时,这个方案就会变得无效,因为XSS可以模拟客户端浏览器执行任意操作。在XSS攻击下,攻击者完成可以请求页面后,读出页面内容的token值,然后再构造出一个合法的请求。这个过程可以称之为XSRF,和CSRF区分。

现代浏览器的cookie有samesite属性,对CSRF防御有些许帮助,samesite有如下属性:

  1. Strict,仅允许第一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致
  2. Lax,允许部分第三方请求携带 Cookie,同站发送和第三方get请求会发送
  3. None,无论是否跨站都会发送 Cookie

7

4. 点击劫持(ClickJacking)

点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

在CSRF攻击的过程中,如果出现用户交互的页面,则攻击可能会无法顺利完成。与之相反,点击劫持没有这个顾虑,它利用的就是与用户产生交互的页面。

攻击方式:

  1. 图片覆盖攻击,css(style) + 图片点击
  2. 拖拽劫持与数据窃取,iframe + 拖拽事件的evet.dataTransfer.getData('Text')

ClickJacking的防御策略:

  1. frame busting,通过JS代码进制iframe的嵌套,但是因为是JS写的,控制能力并不是特别强,有很多方法可以绕过它
  2. X-Frame-Options,是一个http响应头,指示浏览器是否允许一个页面在 <frame>, <iframe>, <embed>,<object> 中展现的标记

X-Frame-Options 是个已广泛支持的非官方标准,可以和 CSP 结合使用。 X-Frame-Options 有三个可能的值:

  1. deny,表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许
  2. sameorigin,表示该页面可以在相同域名页面的 frame 中展示
  3. allow-from {uri},表示该页面可以在指定来源的 frame 中展示

服务器端应用安全

如果你有使用Node作为服务器的经历,那么要小心避开一些安全漏洞。

注入攻击

注入攻击的本质,是把用户输入的数据当做代码执行,违背了“数据与代码分离原则”。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户输入的数据。

1. SQL注入

SQL注入就是在原来的执行语义上添加了额外的语义,导致攻击的发生。

发现SQL注入漏洞的方法有:

  1. 盲注(Blind Injection),使用假命题比如and 1=2并观察返回值来判断是否有攻击漏洞
  2. Timing Attack,通过执行测试函数性能的函数的时间长短来判断是否有攻击漏洞

攻击方式有:

  1. 常见的攻击方式,就是执行额外的语句、系统命令
  2. 攻击存储过程,存储过程本身也可能存在注入漏洞的
  3. 编码问题,基于字符集的攻击
  4. SQL Column Truncation,利用非严格模式下超长值发生截断但是会被插入的漏洞

注入的防御策略:

  1. 使用预编译语句,绑定变量
  2. 使用安全的存储过程,避免在存储过程内使用动态的SQL语句,如果无法避免,应该使用严格的输入过滤或者使编码函数来处理用户的输入数据
  3. 检查数据类型
  4. 使用安全函数,很多数据库厂商都提供了安全的编码函数
  5. 编码问题的解决方案,统一数据库、操作系统、Web应用所使用的字符集,比如UTF-8

2. XML注入

XML注入和HTML注入是相似的,对语言自身的保留字符转移即可。

如:'、"、/、&、<、>

3. 代码注入

如果使用一些可以执行用户输入作为代码的函数,需要谨慎。或者尽量避免这样做。

4. CRLF注入

CR是Carriage Return(ASCII 13, \r),LF是Line Feed(ASCII 10, \n)。

凡是使用CRLF作为分隔符的地方都可能存在CRLF注入。最典型的就是HTTP头部。

对抗CRLF的方法非常简单,只需要处理好"\r"、"\n"两个保留字符即可。

参考

《白帽子讲Web安全》
Web 安全专题

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant