安全
SQL 注入
这是一种比较简单的攻击方式。
如果后台人员使用用户输入的数据来组装SQL查询语句的时候不做防范, 遇到一些恶意的输入, 最后生成的SQL就会有问题。
比如地址栏输入的是:
1 | articlrs/index.php?id=1 |
发送一个get请求, 调用的查询语句是:
1 | sql = "SELECT * FROM articles WHERE id =", $id |
正常情况下, 返回 id = 1 的文章。
如果攻击者想获得所有的文章,语句就可以改成:
1 | articlrs/index.php?id=-1 OR 1 = 1 |
这样就可以了, 为什么呢?
这是因为,id = -1 永远是 false,1=1 永远是true,所有整个where语句永远是ture.
所以 where 条件相当于没有加where条件,那么查询的结果相当于整张表的内容,攻击者就达到了目的。
现在的系统一般都会加入 过滤 和 验证 机制, 可以有效预防SQL注入问题。
XSS
跨网站指令码(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程式的安全漏洞攻击,是代码注入的一种。它允许恶意使用者将程式码注入到网页上,其他使用者在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及使用者端脚本语言。
XSS 分为三种:反射型,存储型和 DOM-based
如何攻击
XSS 通过修改 HTML 节点或者执行 JS 代码来攻击网站。
例如通过 URL 获取某些参数
1 | <!-- http://www.domain.com?name=<script>alert(1)</script> --> |
上述 URL 输入可能会将 HTML 改为
1 | <div><script>alert(1)</script></div> |
这样页面中就凭空多了一段可执行脚本。这种攻击类型是反射型攻击,也可以说是 DOM-based 攻击。
也有另一种场景,比如写了一篇包含攻击代码
1 | <script>alert(1)</script> |
的文章,那么可能浏览文章的用户都会被攻击到。这种攻击类型是存储型攻击,也可以说是 DOM-based 攻击,并且这种攻击打击面更广。
如何防御
最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义
1 | function escape(str) { |
通过转义可以将攻击代码
1 | <script>alert(1)</script> |
变成
1 | // -> <script>alert(1)</script> |
对于显示富文本来说,不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。
1 | var xss = require('xss') |
以上示例使用了 js-xss 来实现。可以看到在输出中保留了 h1 标签且过滤了 script 标签
CSP
内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。
我们可以通过 CSP 来尽量减少 XSS 攻击。CSP 本质上也是建立白名单,规定了浏览器只能够执行特定来源的代码。
通常可以通过 HTTP Header 中的 Content-Security-Policy 来开启 CSP
只允许加载本站资源
1 | Content-Security-Policy: default-src ‘self’ |
只允许加载 HTTPS 协议图片
1 | Content-Security-Policy: img-src https://* |
允许加载任何来源框架
1 | Content-Security-Policy: child-src 'none' |
CSRF
跨站请求伪造,也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。
简单点说,CSRF 就是利用用户的登录态发起恶意请求。
如何攻击
假设网站中有一个通过 Get 请求提交用户评论的接口,那么攻击者就可以在钓鱼网站中加入一个图片,图片的地址就是评论接口
1 | <img src="http://www.domain.com/xxx?comment='attack'" /> |
如果接口是 Post 提交的,就相对麻烦点,需要用表单来提交接口
1 | <form action="http://www.domain.com/xxx" id="CSRF" method="post"> |
如何防御
防范 CSRF 可以遵循以下几种规则:
1.Get 请求不对数据进行修改
2.不让第三方网站访问到用户 Cookie
3.阻止第三方网站请求接口
4.请求时附带验证信息,比如验证码或者 token
点击劫持
click-jacking,也被称为UI-覆盖攻击。
这也是比较常问到的一个问题,也是我们最常见的一种情况。
攻击方式就是在某些操作的按钮上加一层透明的iframe。
点击一下, 就入坑了。
如何防御
常用的两种方式:
- 使用 HTTP 头防御
通过配置 nginx 发送 X-Frame-Options 响应头,这个 HTTP 响应头 就是为了防御用 iframe 嵌套的点击劫持攻击。 这样浏览器就会阻止嵌入网页的渲染。
该响应头有三个值可选,分别是:
- DENY,表示页面不允许通过 iframe 的方式展示。
- SAMEORIGIN,表示页面可以在相同域名下通过 iframe 的方式展示。
- ALLOW-FROM,表示页面可以在指定来源的 iframe 中展示。
更详细的可以查阅 MDN 上关于 X-Frame-Options 响应头的内容。
- 使用 Javascript 防御
判断顶层视口的域名是不是和本页面的域名一致,如果不一致就让恶意网页自动跳转到我方的网页。
1 | if (top.location.hostname !== self.location.hostname) { |
中间人攻击
中间人攻击(Man-in-the-Middle Attack, MITM)是一种由来已久的网络入侵手段,如 SMB 会话劫持、DNS 欺骗等攻击都是典型的MITM攻击。
简而言之,所谓的MITM攻击就是通过拦截正常的网络通信数据,并进行数据篡改和嗅探来达到攻击的目的,而通信的双方却毫不知情。
如何防御
以下是针对防止中间人攻击的一些建议:
- 确保当前你所访问的网站使用了HTTPS
- 如果你是一个网站管理员,你应当执行HSTS协议
- 不要在公共Wi-Fi上发送敏感数据
- 如果你的网站使用了SSL,确保你禁用了不安全的SSL/TLS协议。
- 不要点击恶意链接或电子邮件。
还有一个容易被忽略的漏洞
window.opener
带有 target=”_blank” 跳转的网页拥有了浏览器 window.opener 对象赋予的对原网页的跳转权限,这可能会被恶意网站利用,例如一个恶意网站在某 UGC 网站 Po 了其恶意网址,该 UGC 网站用户在新窗口打开页面时,恶意网站利用该漏洞将原 UGC 网站跳转到伪造的钓鱼页面,用户返回到原窗口时可能会忽视浏览器 URL 已发生了变化,伪造页面即可进一步进行钓鱼或其他恶意行为:
代码如下
1 | <script language="javascript"> |
想象一下,你在浏览淘宝的时候,点击了网页聊天窗口的一条外链,出去看了一眼,回来之后淘宝网已经变成了另一个域名的高仿网站,而你却未曾发觉,继续买东西把自己的钱直接打到骗子手里。
如何修复
为 target=”_blank” 加上 rel=”noopener noreferrer” 属性。
1 | <a href="外跳的地址" rel="noopener noreferrer">外跳的地址a> |
缺点: 为禁止了跳转带上 referrer,目标网址没办法检测来源地址。
还有一种方法是,所有的外部链接都替换为内部的跳转连接服务,点击连接时,先跳到内部地址,再由服务器 redirect 到外部网址。
现在很多站点都是这么做的, 不仅可以规避风险,还可以控制非法站点的打开:
1 | "/redirect?target=http%3A%2F%2Fxxx.yyy.com"> |
SameSite
可以对 Cookie 设置 SameSite 属性。该属性设置 Cookie 不随着跨域请求发送,该属性可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。
验证 Referer
对于需要防范 CSRF 的请求,我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的。
Token
服务器下发一个随机 Token(算法不能复杂),每次发起请求时将 Token 携带上,服务器验证 Token 是否有效。
密码安全
密码安全虽然大多是后端的事情,但是作为一名优秀的前端程序员也需要熟悉这方面的知识。
上文介绍了了一些常见的前端安全方面的知识及如何防御这些攻击,应对面试的话,基本上也算够用了。