在今天的数字世界中,在上网时,人们常常忽略了不安全网站的风险。虽然开发人员应当解决这些漏洞问题,但很少有人愿意承认他们在网络安全领域经验不足。理解常见的网络威胁并知道如何减轻这些威胁,这正是资深专业人士与初级人员之间的重要区别。
今天我们来聊聊不同的网络漏洞,例如DDoS攻击、SQL注入、开放重定向漏洞、XSS、CSRF和点击劫持。它们可能造成的危害以及如何避免。我们将从两种不同的角度来看这个问题——黑客的攻击手段和安全专家的防御策略。到了文章的最后,你就能知道怎么应对和解决每一个问题了。
我们直接开始。
拒绝服务攻击, 分布式拒绝服务攻击拒绝服务攻击(DoS) 是一种网络攻击,旨在让服务器无法使用,通常通过发送大量HTTP请求来压垮服务器。
DDoS攻击(分布式拒绝服务攻击), 是一种更高级的拒绝服务攻击,当攻击来自多台机器时。
用大量的请求轰炸你的服务器,让它挂掉 😂。
这是一个无限循环,它会不停地从'https://example.com'获取数据。
while (true) {
fetch('https://example.com');
}
影响力(炸裂了) 🧨
一次成功的DDoS攻击可能造成严重后果,包括:
- 服务器变慢。如果内存或 CPU 资源耗尽,会导致操作延迟等问题
- 服务器不可用状态。攻击的主要目的是让服务器无法运行
以下是一些防止DDoS攻击最常见的方式。
- 研究不同的限速策略,并选择适合您的策略来使用
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("fixedWindowPolicy", policy =>
{
policy.允许请求数 = 100; // 固定窗口内允许的最大请求数量
policy.窗口时间 = TimeSpan.FromMinutes(1); // 窗口时间(比如,1分钟)
});
});
- 配置监控以发现异常流量模式,并迅速响应可能的攻击,以便及时应对。
- 考虑使用付费的DDoS防护服务以防御恶意流量和可疑活动。配置reCAPTCHA等工具来检测机器人等。
收到 HTTP 请求是很常见的事情。由于这种攻击的特性,防止这种攻击可能很有挑战性;然而,有一些策略可以帮助你的服务器更加强大。
- 优化后端代码,并寻找那些占用大量资源且可以改进的端点
- 优化前端代码,确保没有冗余的调用或递归调用不会占用服务器资源
- 按需扩展服务器,既包括横向也包括纵向
- 当服务器不可用时重试HTTP请求很常见。确保每次重试之间有随机延迟,以免过多请求压垮自己的服务器
var 重试策略 = 策略对象
.处理异常<NetworkException>()
.等待并重试策略(重试次数 = 5, () =>
{
// Adding random delay to avoid synchronized retries
int 随机延迟 = new Random().Next(0, 1000);
return TimeSpan.FromMilliseconds(随机延迟);
});
- 定期进行负载测试,看看系统能承受多少请求和活跃用户。例如,可以看看系统能处理多少请求和活跃用户。
SQL注入攻击是一种安全漏洞,当攻击者能够通过用户输入插入或操纵SQL语句时,这种漏洞就会发生。
- 比如说你有一个页面,有一个搜索框用于搜索电子邮件的用户。服务器上执行如下 SQL 查询:
var sql = $@"
SELECT *
FROM [Users]
WHERE [Email] = '{inputEmail}'";
// 从Users表中选择所有电子邮件等于输入电子邮件的记录。
return db.Execute(sql);
- 尝试将下一个值输入到该输入框中。
john.doe@mail.com“ 或 '1'='1”
或者试试这个 😈?
john.doe@mail.com'; 删掉表 [Users];
3. 如果你的服务器返回了多余的记录,那可能意味着存在SQL注入。
影响啥 🧨 (注:此符号表示“爆炸”)这种类型的攻击一般都瞄准数据库:
- 入侵者可以获取敏感数据,例如用户名、密码、信用卡详情、个人信息等
- 黑客可以执行更新、删除或插入命令。这可能会损坏数据或改变应用程序的功能
- SQL注入攻击可以通过创建资源密集型查询、删除关键数据或插入多余的记录来造成拒绝服务攻击(DoS攻击)
- 不要使用纯SQL查询和拼接字符串。清理输入或使用默认转义参数的ORM。
var param = new
{
InputEmail = inputEmail,
};
var sql = $@"
SELECT *
FROM [Users]
WHERE [Email] = @{nameof(param.InputEmail)}";
return db.Execute(sql, param); // param 已经经过了 sanitization 处理
开放重定向
开放重定向漏洞是指当应用程序被攻击者注入代码时,用户会被重定向到攻击者的网站。
- 找出您应用程序中所有可以输入网址的位置,看看哪些位置在重定向中被使用。
. . .
string redirectUrl = Request.QueryString["url"];
return Redirect(redirectUrl);
3. 尝试输入恶意网址,看看用户是否会被重定向到有害网站。如果成功了,很好;这就说明你可能遭受开放重定向攻击的威胁 😁
例如:```
https://my.site.com/login?redirectURL=https://attacker.com
## 冲击 🧨
一个开放重定向漏洞(Open Redirect漏洞)通常会导致网络钓鱼攻击。攻击者可能会建立一个模仿您网站的网站,诱使用户泄露个人信息。
## 预防意外
为了防止开放重定向的漏洞,仅允许重定向到预先定义好的可信URL,清理输入。
public class AccountController : Controller
{
. . .
[HttpPost]
public IActionResult SubmitForm(string redirectUrl)
{
var allowedUrls = new List<string>
{
"https://your.trusted.domain.com",
"https://in.domain.we.trust.com",
};
if (allowedUrls.Contains(redirectUrl))
{
// 跳转到允许的URL
return Redirect(redirectUrl);
}
// 如果验证失败,重定向到默认页面
return Redirect("/Home/Index");
}
}
# XSS攻击
**跨站脚本攻击(XSS)** 是一种攻击方式,当恶意的 JavaScript 代码被注入到网站代码中,并在用户的浏览器中执行。

## 找找🔍
1. 你的项目里很可能包含一个WYSIWYG编辑器。它可能以HTML格式存储文本,并在其他页面上渲染。
试试看在编辑器中输入这个简单的脚本,然后保存它,
<img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="x" onerror="alert(42)">` (这是一张图片的HTML代码,其中如果图片无法加载,将弹出一个警告框显示数字42。)
2\. 打开显示 HTML 的页面。
3\. 当你看到 `alert` 消息,恭喜,这是跨站脚本攻击。
## 影响力 🧨
(Note: The emoji is retained as per the original text, despite the expert suggestion to remove it, to stay true to the source text's elements.)
潜在的损害可能各不相同,这取决于攻击者的意图。
* 脚本可能会导致递归,从而逐渐破坏用户的程序体验
* 如果将 [JWT 令牌](https://medium.com/@iamprovidence/token-gang-bearer-token-reference-token-opaque-token-self-contained-token-jwt-access-token-6e0191093cd0#63ab) 存储在本地存储中,攻击者的脚本可以读取该令牌并将其发送到他的服务器
* 攻击者可以监视用户的行为
* 攻击者可以利用他人的浏览器发起 DDoS 攻击
* 脚本可以修改网页内容
* 等等
## 预防 👮♂️ (注:用了警察的图标来替代原文的消防员图标,更符合“预防”这一动作)
* 使用带有 `HttpOnly` 和 `Secure` 标记的 [cookies](https://medium.com/@iamprovidence/authentication-history-basic-digest-cookie-session-token-jwt-api-key-55d6c21be90b#c9ff) 来,这样攻击者的脚本就无法读取你的 cookie
public void ConfigureServices(IServiceCollection services)
{
. . .
// 配置Cookie策略选项
services.Configure<CookiePolicyOptions>(options =>
{
// 设置HttpOnly策略为Always
options.HttpOnly = HttpOnlyPolicy.Always;
// 设置安全策略为Always
options.Secure = CookieSecurePolicy.Always;
});
. . .
}
* 对用户输入进行清理并检查,以避免潜在危险的HTML标签,确保网站安全。
var sanitizer = new HtmlSanitizer(); // 创建一个HtmlSanitizer对象,用于清理HTML内容
string safeInput = HttpUtility.HtmlEncode(userInput); // 使用HttpUtility.HtmlEncode方法对用户输入进行编码,以确保其安全
\- 不要自己写 sanitizer。使用已经经过实战考验的现成库。
\- 不仅要对前端进行 sanitization,还要对后端进行 sanitization。攻击者可以通过直接向服务器发送请求来绕过用户界面。
* 不要用不安全的方法渲染 HTML。使用会自动进行输出安全处理的框架和库。
@Html.RenderHtmlSafe(Model.Property)
仍然需要清理输出,以防黑客通过其他手段注入脚本,比如SQL注入之类的攻击。
* 技术硬核的开发者还可以在 HTTP 响应里加 `Content-Security-Policy` 头
public void 配置(I应用构建者 app, IWeb主机环境 env)
{
. . .
app.Use(async (context, 下一个) =>
{
context.Response.Headers.ContentSecurityPolicy = "connect-src https://api.example.com; script-src https://cdn.example.com"; // 连接源设置为https://api.example.com,脚本源设置为https://cdn.example.com
await 下一个();
});
. . .
}
它指示浏览器可以使用哪些来源加载内容。在上面的例子中,发出的头部信息只允许客户端应用程序只能向 `https://api.example.com` 发送请求,并可以从 `https://cdn.example.com` 加载 js 脚本。
# CSRF (XSRF),又称跨站请求伪造攻击
**CSRF(跨站请求伪造)** 攻击通过让已认证的用户在网站上执行不需要的操作来误导他们执行这些操作。

这次攻击主要瞄准[cookies](https://medium.com/@iamprovidence/authentication-history-basic-digest-cookie-session-token-jwt-api-key-55d6c21be90b#c9ff),因为它们被浏览器自动发送。[JWT 令牌](https://medium.com/@iamprovidence/authentication-history-basic-digest-cookie-session-token-jwt-api-key-55d6c21be90b#6fba) 不会受到 CSRF 的攻击。
## 查找 🔍
1. 想象我们有一个银行网站,实现了基于[cookie](https://medium.com/@iamprovidence/authentication-history-basic-digest-cookie-session-token-jwt-api-key-55d6c21be90b#c9ff)的认证。
2. 我们知道用户已经登录了他的银行账户。
3. 我们可以给用户发送一封邮件,邮件中包含一个链接,点击该链接将会把钱转到我们的卡上:
<html>
<body>
<!-- the valid bank URL -->
<form action="https://my.bank/transfer?amount=123" method="POST">
<button type="submit">点这里</button>
</form>
</body>
</html>
4\. 由于用户已登录,浏览器会自动在请求中携带 cookie,并代用户执行一些不需要的操作。
## 冲击来了 🧨
这次攻击的主要受害者是已登录的用户,主要因为:
* 攻击者可以利用用户的账号发起支付
* 攻击者可能会更改账户信息,如密码或邮箱地址,从而控制用户账号
* 攻击者可以修改重要数据,如个人资料设置或其他敏感信息,用户却不知道
## 防火 🚒
为了CSRF攻击能成功,攻击者必须找到一个可重复的网络请求。我们的目标是保护这些端点的安全。
* 将 GET 方法实现为无副作用的只读操作
* 有时你必须实现执行某些动作的 GET 端点
一种常见的预防措施是包含一个防伪造令牌。例如,可以添加一个基于其他参数的随机哈希。
请点击以下链接重置密码: https://my.bank/reset-password?account=john.doe@mail.com&hash=lL73BSpa7h
稍后再检查哈希是否正确
public class AccountController : Controller
{
. . .
[HttpGet]
public ActionResult 重置密码(string account, string hash)
{
var 正确的哈希值 = HashService.Create(account);
if (正确的哈希值 != hash)
{
return RedirectToAction("错误");
}
return View();
}
}
由于你用的哈希算法攻击者不知道,因此他们就没法伪造你的URL了。
* 类似地,POST 请求可以用防止伪造令牌保护起来。
通常,框架都提供了防止CSRF攻击的令牌的支持。例如,在ASP.NET MVC中,您可以使用`@Html.AntiForgeryToken()`辅助程序在HTML中使用:
<form action="https://my.bank/transfer?amount=123" method="POST">
@Html.AntiForgeryToken() <!-- 添加了防伪造令牌 -->
<button type="submit">点这里</button>
</form>
这在后端得到了验证:
[HttpPost]
[ValidateAntiForgeryToken] // 防止 CSRF 攻击注释
public ActionResult ActionName(string username)
{
// 这里添加你的逻辑代码
return View();
}
* 使用 `**SameSite**` cookie 属性来控制浏览器在什么情况下发送 cookie。它可以接受以下三个值之一:
— `**None**` — cookie 会在所有请求中发送
— `**Strict**` — cookie 只会在同源请求中发送
— `**Lax**`(默认) — cookie 不会被发送到大多数跨域请求中,比如由第三方域名发起的请求。但是,如果请求是由用户点击链接(如顶级导航)触发的,则会发送 cookie。
* 实现 CORS(跨源资源共享)功能。
CORS 是浏览器实现的一种安全功能,用来控制哪些域名可以向服务器发送请求。
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("MyCorsPolicy", builder =>
{
builder
.WithOrigins("https://example.com") // 允许的来源包括:
.AllowAnyHeader()
.AllowAnyMethod();
});
});
. . .
}
请注意,CSRF攻击仍然可能来自同一个源,这意味着CORS无法阻止这些攻击。CORS仅解决跨源问题,而不是同源攻击。结合CORS和其他安全措施一起使用。
# 点击劫持攻击
**点击劫持攻击**是指攻击者利用透明层来欺骗用户,使其点击他们以为是在当前页面上的按钮或链接。

该攻击与**CSRF**相似,因为两者都骗用户执行意外的操作。但它们的工作原理不同,且针对的是不同的漏洞。
## 查找🔍找找看
1. 给一个无辜的用户发送电子邮件(或采取其他类似手段,例如诱使他访问你的网站等)。
2. 在这封邮件中添加一个看起来无害的按钮(例如,“点击这里”或“取消订阅”)。
3. 在这个按钮上方放置一个透明的 `<iframe>` 标签,指向我们的网站。
<html>
<style>
.iframe {
opacity: 0;
}
</style>
<body>
<iframe class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="https://my.bank/transfer?amount=123"></iframe>
<button>点击这里!</button>
</body>
</html>
4\. 当用户尝试点击按钮时,实际上点击到了`iframe`,这会在你的网站上执行意外的动作。
## 冲击 🧨
这次攻击也是针对终端用户的。
* 受害者可能不小心进行无意的购买、订阅服务,甚至在不知情的情况下转账
* 点击劫持可能导致更改账户设置、启用权限或使攻击者获得访问权限等行为
* 用户可能在不知情的情况下执行诸如点赞帖子、分享内容、订阅新闻通讯等操作
## 防火 👨🚒 :
* 使用 `**SameSite**` cookie 属性 (`**None**`,`**Strict**`,`**Lax**`)
* (旧版的)添加 `X-Frame-Options` HTTP 头,用于控制网页是否可以在 `<iframe>` 中显示:
— `DENY` — 防止页面被任何框架加载
— `ALLOW-FROM _< 源>_` — 允许页面仅在特定白名单中的来源中加载
— `SAMEORIGIN` — 允许页面仅在与自身相同来源的框架中加载
public class 启动类
{
. . .
public void 配置(IApplicationBuilder app)
{
. . .
app.使用(async (context, next) =>
{
context.Response.Headers.XFrameOptions = "拒绝";
await next();
});
. . .
}
}
虽然此标题得到了广泛的支持,但它不是官方的HTTP标准,可能在某些浏览器中无法正常运作。
* 添加 `Content-Security-Policy` HTTP 头部,使用 `frame-ancestors` 指令来控制 iframe 嵌入内容的权限:
— `frame-ancestors ‘none’` — 禁止任何网站使用框架嵌入
— `frame-ancestors www.example.com _< origin>_` — 允许指定来源的框架嵌入
— `frame-ancestors ‘self’` — 仅允许嵌入自身的内容
# 结尾一下
你看,安全其实没那么复杂 🙃。现在你知道了常见的 web 漏洞,如何检测和修复它们,你学到了如何……等等,等等。我刚刚是教了你如何搞垮别人的网站了吗 🤔?别这么做。如果你真做了,也别告诉我是我教你 😅。
当然,在实际操作中,情况要复杂得多。这只是冰山的一角。还有其他的漏洞、网络攻击和威胁,所有这些都可以在另一篇文章中详细探讨 😉。

在评论区告诉我你在项目中多常遇到安全问题,告诉我吧 💬
如果喜欢这篇文章,就给我点掌声 👏
如果你喜欢这篇文章,就给我点个赞吧 ☕️
别忘了关注我,以后还有更多安全小贴士哦 ✅
你再看看这篇文章,我这边接着跑🏃♂️🚓
共同学习,写下你的评论
评论加载中...
作者其他优质文章