常见的网络攻击

114 阅读7分钟

SQL 注入

核心就是让 web 服务器执行攻击者希望的 sql 语句,以便得到数据库中的数据或者对数据库中的数据进行增删改查。

实现方式

将 sql 语句放入 form 表单或者是请求参数中提交到后端服务器,后端服务器如果未做输入的安全校验直接将变量取出进行数据库查询则极容易中招。

防御

  • 严格限制 web 应用操作数据库的权利

  • 后端代码检查数据的合法性

  • 对数据库的特殊字符进行转译处理

  • 所有查询语句建议使用数据库提供的参数化查询接口,参数化的语句使用的是参数而不是用户输入的变量嵌入到 SQL 语句中,即不要直接拼接 SQL 语句

XSS - 跨站脚本攻击

XSS 攻击的核心就是将可执行的前端代码(一般是 JS)插入到网页中。简单的说就是攻击者希望你的浏览器可以执行他的 JS 代码,一般分为两种:

反射型

  • 攻击者将 JS 代码作为请求参数放在 URL 中诱导用户去点击 http://localhost:8080/test?name=<script>alert("you are under attack!")</script>

  • 用户点击后该 JS 作为请求传递给后端

  • 后端没有检查过滤,简单处理后放入网页正文中返回给浏览器(比如这里可能就是将 name 的值插入到页面中)

  • 浏览器解析返回的网页,中招!

存储型

上述方式是直接经过服务器转手后返回给浏览器执行。存储型与之的区别在于能够将攻击的脚本存储到数据库中,在后面查询时再将攻击脚本渲染进网页返回给浏览器触发执行

  • 攻击者网页回帖,帖子中包含了 js 脚本
  • 回帖提交给服务器之后,存储至数据库
  • 其他网友查看帖子,后台查询该帖子的回帖内容,构建完整网页,返回给浏览器
  • 该网友的浏览器渲染返回的页面,中招!

防御手段

  • 尽量不要从 url,document.referrer,document.forms 中获取数据直接渲染

  • 尽量不要使用 document.write、eval、setTimeout、setInterval、document.writeIn、innerHTML、new Function()等可以执行字符串的方法

  • 对需要在 DOM 中渲染的字符串进行转译

CSP(Content-Security-Policy)

CSP 本质上就是建立白名单,开发者告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是浏览器自己实现的。可以通过这种方式来尽量减少 XSS 攻击。

通常有两种方式可以设置 CSP

  • 设置 HTTP Header:Content-Security-Policy
  • 设置 meta 标签
例子
  1. 只允许加载本站资源
Content-Security-Policy: default-src 'self'
  1. 只允许加载 https 协议图片
Content-Security-Policy: img-src https://*
  1. 允许加载来自任河源的框架
Content-Security-Policy: child-src 'none'

特殊字符转译

不要相信用户的输入,转译输入的内容

HttpOnly Cookie

这个是预防 xss 获取用户 cookie 的最好的手段,添加该属性表明禁止 JS 来操作 cookie,也就是无法通过 document.cookie 来访问 cookie,此 cookie 只能服务器来操作

CSRF - 跨站请求伪造

利用用户已登陆的身份,在用户毫不知情的情况下,以用户的名义进行非法操作。

完成 CSRF 的三个条件

  • 用户登陆受信任的网站 A 并生成了 cookie
  • 在不登出 A 的情况下(也就是 cookie 生效的情况下),访问危险网站 B(B 站点内部会请求 A 站点)
  • 站点 A 没有做任何的 CSRF 防御

看一个例子,我们登陆了一个转账页面,突然眼前一亮惊现"XXX 隐私照片,不看后悔一辈子"的链接,耐不住内心躁动,立马点击了该危险的网站,但当这页面一加载,便会执行 submitForm 这个方法来提交转账请求,从而将 10 块转给黑客。

防御

SameSite Cookie

可以对 cookie 设置 SameSite 属性,表示该 Cookie 不会随着跨域请求发送,可以很大程度的减少 CSRF 攻击

Referer Check

HTTP Referer 是请求头的一个字段,告诉服务器请求是从哪个页面发送过来的(是一个 url 地址)。可以通过检查请求的来源来防御 CSRF 攻击。

但是当页面从 https 跳转到 http,浏览器出于安全考虑,就不会发送 referer,服务器就无法进行 check 了。出于这个原因,无法完全依赖 referer 来作为防御 CSRF 的手段

Token

浏览器在请求参数中加入一个随机产生的 Token,并在服务端建立一个拦截器来验证这个 Token。服务器读取浏览器当前域 cookie 中的 token 值,与请求中的 token 值进行对比,一致时请求成功,否则拒绝访问

token 可以在用户登陆的时候生成存放于 session 或者 cookie 中,每次请求的时候服务器都从 session/cookie 中取出 token 与请求中的 token 进行比较。由于 token 的存在攻击者无法构造出一个完整的请求 URL,所以可以一定程度的防范 CSRF 攻击

验证码

应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制 CSRF 攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。

点击劫持

视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入到自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击

特点

  • 隐蔽性高,骗取用户操作
  • 利用 iframe 或者其他标签的原理

原理

用户在登陆网站 A 的系统后,被攻击者诱惑打开第三方网站,而第三方网站通过 iframe 引入了 A 网站,用户在第三方网站中点击被修饰过的按钮,实际上点击的是 A 网站的按钮。

比如说在优酷上发布了一些视频,想让更多的人关注它,就可以通过点击劫持来实现。

防御

X-Frame-Options

它是一个响应头,为了防止 iframe 的嵌套点击劫持

三个值可以选

  • deny 表示页面不允许通过 iframe 的方式展示
  • sameorigin 表示页面可以在相同的域名下通过 iframe 嵌套展示
  • allow-from 表示页面可以在指定来源的 iframe 展示 X-Frame-Options: allow-from example.com/

URL 跳转漏洞

借助未验证的 URL 跳转,将应用程序引导到不安全的第三方区域,从而导致安全问题

原理

黑客利用 URL 跳转的漏洞来诱导安全意识低的用户点击,导致用户的信息泄漏或者资金流失。黑客构造恶意的连接(连接需要进行伪装,尽可能迷惑),发到贴吧或者是群里。

用户点击之后,经过服务器或者浏览器解析后,跳转到恶意的页面中。

恶意的连接需要伪装,所以经常的做法就是在一个熟悉的连接后面加上一个恶意的地址,这样才能迷惑用户

http://gate.baidu.com/index?act=go&url=http://t.cn/RVTatrd
http://qt.qq.com/safecheck.html?flag=1&url=http://t.cn/RVTatrd
http://tieba.baidu.com/f/user/passport?jumpUrl=http://t.cn/RVTatrd

实现方式

  • header 跳转
  • JavaScript 跳转
  • meta 跳转
<?php
$url=$_GET['jumpto'];
header("Location: $url");
?>
http://www.wooyun.org/login.php?jumpto=http://www.evil.com

用户认为 www.wooyun.org 是可信的,但是最终跳转到的是www.evil.com页面

防御

referer 限制

如果确定 url 参数进入的来源,我们就可以通过该方式来实现安全限制,保证 url 的有效性,避免恶意用户生成自己的连接

Token

我们保证生成的所有连接都来自于我们可信域的,通过在生成的链接里加入用户不可控的 token 来对生成的连接进行校验

OS 命令注入攻击

OS 命令注入和 SQL 注入差不多,只不过 SQL 注入是针对数据库的,而 OS 注入是针对操作系统的。

OS 命令注入是指通过 web 应用,执行非法的操作系统命令达到攻击的目的

原理

黑客构造命令提交给 web 程序,web 应用程序提取黑客构造的命令,拼接到被执行的命令中,因黑客注入的命令打破了原有的命令结构,导致 web 程序执行了额外的命令,最后 web 应用程序将执行的结果响应输出到页面中

需求:用户提交一些内容到服务器,然后在服务器执行一些命令去返回一个结果给用户

// 以 Node.js 为例,假如在接口中需要从 github 下载用户指定的 repo
const exec = require("mz/child_process").exec;
let params = {
  /* 用户输入的参数 */
};
exec(`git clone ${params.repo} /some/path`);

如果 params.repo 传入的是 github.com/admin/admin… 确实能从指定的 git repo 上下载到想要的代码。

但是如果 params.repo 传入的是 github.com/xx/xx.git && rm -rf /* && 恰好你的服务是用 root 权限起的就糟糕了。

防御

  • 后端对前端提交的内容进行规则限制
  • 在调用系统命令前对所有传入的参数进行命令行参数转义过滤
  • 不要直接拼接命令语句,借助一些工具做拼接、转义预处理。例如 nodejs 的 shell-escape npm 包