VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#网络编程之防御网络攻击(DDoS、SQL注入、XSS)

第19章 防御网络攻击
19.1 防御网络攻击(DDoS、SQL注入、XSS)
一、我踩过的攻击坑:从数据库被拖库到网站瘫痪
刚做第一个电商网站时,为了图快用拼接SQL查询订单,结果被SQL注入,数据库被拖库,用户的手机号、地址全部泄露,赔了用户50万;后来做论坛,没过滤用户输入的HTML,被XSS攻击,用户账号被盗,发了一堆垃圾广告,被搜索引擎降权;再后来网站流量起来,又被DDoS攻击,网站瘫痪了3小时,损失了10万订单。踩过这些坑后,我才明白:网络攻击离我们并不远,小网站也会被盯上,防御攻击不是“高大上的技术”,而是要把基础vb.net教程C#教程python教程SQL教程access 2010教程防御做到位。这节我把自己从“被攻击到崩溃”到“防御体系完善”的踩坑经验揉进去,用大白话讲透SQL注入、XSS、DDoS的原理,结合C#实战代码逐行讲解防御方法,以及常见坑和最佳实践,让你的网站像银行一样安全。
二、SQL注入:最常见的攻击,用参数化查询就能防99%
SQL注入是黑客通过在用户输入中插入SQL语句,让服务器执行恶意SQL——比如用户在登录框输入' OR 1=1 --,如果你的代码用拼接SQL,就会变成SELECT * FROM Users WHERE Username='' OR 1=1 --' AND Password='xxx',直接登录成功,甚至删除数据库。
核心原理(大白话)
比如你的代码是这样的:
csharp
string sql = $"SELECT * FROM Users WHERE Username='{username}' AND Password='{password}'";
黑客输入username=' OR 1=1 --,SQL就变成:
sql
SELECT * FROM Users WHERE Username='' OR 1=1 --' AND Password='xxx'
--是SQL注释,后面的内容被忽略,所以这条SQL会返回所有用户,黑客直接登录成功。
实战1:用参数化查询防SQL注入(ADO.NET)
csharp

	using System;
	using System.Data.SqlClient;
	
	namespace SqlInjectionDefense;
	
	class AdoNetExample
	{
	static void Main(string[] args)
	{
	// 黑客输入的恶意用户名
	string maliciousUsername = "' OR 1=1 --";
	string password = "anypassword";
	
	// 错误写法:拼接SQL,会被注入
	string badSql = $"SELECT COUNT(*) FROM Users WHERE Username='{maliciousUsername}' AND Password='{password}'";
	Console.WriteLine($"恶意SQL:{badSql}");
	// 执行这条SQL会返回所有用户,黑客登录成功
	
	// 正确写法:参数化查询,防止注入
	string goodSql = "SELECT COUNT(*) FROM Users WHERE Username=@Username AND Password=@Password";
	string connectionString = "Server=.;Database=DemoDB;Trusted_Connection=True;";
	
	using (var conn = new SqlConnection(connectionString))
	{
	conn.Open();
	using (var cmd = new SqlCommand(goodSql, conn))
	{
	// 添加参数,SQL Server会自动处理转义,防止注入
	cmd.Parameters.AddWithValue("@Username", maliciousUsername);
	cmd.Parameters.AddWithValue("@Password", password);
	
	int count = (int)cmd.ExecuteScalar();
	Console.WriteLine($"参数化查询结果:{count}(0表示登录失败,正确防御了注入)");
	}
	}
	}
	}

代码逐行讲解:
1.拼接SQL的问题:恶意输入会被当成SQL语句的一部分执行,导致注入;
2.参数化查询:用@Username代替直接拼接,SQL Server会把参数当成数据,而不是SQL语句的一部分,自动处理转义(比如把'转成''),防止注入;
3.AddWithValue:添加参数,参数值会被安全地传递给SQL Server,不会被解析成SQL语句。
我踩过的坑:一开始用存储过程,以为存储过程能防注入,结果在存储过程里用了EXEC('SELECT * FROM Users WHERE Username=' + @Username),还是被注入了——存储过程如果用动态SQL拼接,同样会被注入,必须用参数化!
实战2:用EF Core防SQL注入(ORM的优势)
EF Core的LINQ查询默认是参数化的,自动防注入:
csharp

	using System;
	using System.Linq;
	using Microsoft.EntityFrameworkCore;
	
	namespace EFCoreExample;
	
	public class User
	{
	public int Id { get; set; }
	public string Username { get; set; }
	public string Password { get; set; }
	}
	
	public class AppDbContext : DbContext
	{
	public DbSet<User> Users { get; set; }
	
	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
	{
	optionsBuilder.UseSqlServer("Server=.;Database=DemoDB;Trusted_Connection=True;");
	}
	}
	
	class EFCoreDefense
	{
	static void Main(string[] args)
	{
	string maliciousUsername = "' OR 1=1 --";
	string password = "anypassword";
	
	using (var db = new AppDbContext())
	{
	// LINQ查询自动参数化,防注入
	var user = db.Users.FirstOrDefault(u => u.Username == maliciousUsername && u.Password == password);
	Console.WriteLine($"EF Core查询结果:{(user == null ? "登录失败" : "登录成功")}");
	
	// 注意:如果用FromSqlRaw拼接SQL,同样会被注入,必须用参数化
	// 错误写法:db.Users.FromSqlRaw($"SELECT * FROM Users WHERE Username='{maliciousUsername}'");
	// 正确写法:db.Users.FromSqlRaw("SELECT * FROM Users WHERE Username=@Username", new SqlParameter("@Username", maliciousUsername));
	}
	}
	}

代码逐行讲解:
1.LINQ查询:EF Core会把LINQ转换成参数化SQL,自动防注入,比如u.Username == maliciousUsername会被转换成@p0参数;
2.FromSqlRaw的注意事项:如果必须用原生SQL,一定要用参数化,不能拼接,否则会被注入;
3.ORM的优势:大部分ORM(EF Core、Dapper)都默认支持参数化查询,能有效防止SQL注入,推荐使用ORM,减少手动拼接SQL的机会。
拓展知识:SQL注入的变种
1.盲注:如果网站没有返回错误信息,黑客用AND 1=1、AND 1=0判断SQL是否执行成功,慢慢猜数据库内容;
2.时间盲注:用WAITFOR DELAY '0:0:5',通过响应时间判断SQL是否执行成功;
3.报错注入:用CAST((SELECT Username FROM Users LIMIT 1) AS INT),通过错误信息获取数据库内容。
最佳实践:
1.永远用参数化查询,不要拼接SQL;
2.用ORM代替手动写SQL;
3.最小权限原则:数据库用户只给必要的权限(比如SELECT、INSERT),不要给SA权限;
4.输入验证:限制用户输入的长度、格式(比如用户名只能是字母和数字);
5.输出编码:如果必须显示用户输入的SQL结果,要进行HTML编码,防止XSS。
三、XSS攻击:用户输入的HTML被执行,用编码就能防
XSS(跨站脚本攻击)是黑客在用户输入中插入恶意HTML/JavaScript,当其他用户访问时,恶意脚本被执行——比如黑客在论坛发帖子,内容是,如果网站没过滤,其他用户打开帖子时会弹出alert,甚至被窃取Cookie,账号被盗。
核心原理(大白话)
网站把用户输入的内容直接显示在页面上,没有过滤HTML标签,导致恶意脚本被浏览器执行。比如:
csharp

	string userInput = "<script>alert('XSS')</script>";
	Response.Write($"用户评论:{userInput}");

浏览器会执行);
2.存储型XSS:恶意脚本被存储在数据库中,其他用户访问时执行(比如论坛帖子、评论);
3.DOM型XSS:恶意脚本通过修改页面DOM执行,不需要服务器参与(比如前端用innerHTML渲染用户输入)。
实战2:用ASP.NET Core防XSS攻击

  1. 输入验证与输出编码(服务器端)
    csharp
	using Microsoft.AspNetCore.Mvc;
	using System.Text.Encodings.Web;
	using System.Text.RegularExpressions;
	
	namespace XssDefense.Controllers;
	
	public class HomeController : Controller
	{
	private readonly HtmlEncoder _htmlEncoder;
	
	// 注入HtmlEncoder,用于HTML编码
	public HomeController(HtmlEncoder htmlEncoder)
	{
	_htmlEncoder = htmlEncoder;
	}
	
	// 反射型XSS防御:输出编码
	public IActionResult Search(string keyword)
	{
	// 错误写法:直接输出用户输入,会被XSS
	// ViewData["Result"] = $"搜索结果:{keyword}";
	
	// 正确写法:HTML编码,把<转成&lt;,>转成&gt;,脚本不会被执行
	string encodedKeyword = _htmlEncoder.Encode(keyword);
	ViewData["Result"] = $"搜索结果:{encodedKeyword}";
	return View();
	}
	
	// 存储型XSS防御:输入验证+输出编码
	[HttpPost]
	public IActionResult PostComment(string comment)
	{
	// 输入验证:禁止HTML标签
	if (Regex.IsMatch(comment, @"<[^>]+>"))
	{
	ModelState.AddModelError("comment", "评论不能包含HTML标签");
	return View();
	}
	
	// 存储到数据库(这里省略存储逻辑)
	// db.Comments.Add(new Comment { Content = comment });
	// db.SaveChanges();
	
	// 输出编码:即使输入验证被绕过,编码也能防止XSS
	string encodedComment = _htmlEncoder.Encode(comment);
	ViewData["Comment"] = $"你的评论:{encodedComment}";
	return View();
	}
	}

代码逐行讲解:
1.HtmlEncoder.Encode:把HTML特殊字符转成实体编码,比如<转成&lt;,>转成&gt;,这样浏览器会把<script>当成普通文本显示,不会执行;
2.输入验证:用正则表达式禁止HTML标签,作为第一道防线,即使编码被绕过,输入验证也能拦截;
3.双重防御:输入验证+输出编码,是防XSS的黄金组合——不要只依赖输入验证,因为黑客可以用编码绕过(比如<script>),输出编码是最后一道防线。
我踩过的坑:一开始用正则表达式过滤HTML标签,以为能防所有XSS,结果黑客用javascript:alert('XSS')作为链接,还是被执行了——输入验证不能覆盖所有情况,输出编码才是最可靠的!
2. 用CSP(内容安全策略)防XSS(浏览器端)
CSP是浏览器的安全机制,限制页面加载的资源(比如脚本、样式、图片),防止恶意脚本执行。在ASP.NET Core中配置CSP:
csharp

	// Program.cs
	builder.Services.AddControllersWithViews(options =>
	{
	options.Filters.Add(new SecurityHeadersAttribute());
	});
	
	// 自定义安全头过滤器
	public class SecurityHeadersAttribute : ActionFilterAttribute
	{
	public override void OnResultExecuting(ResultExecutingContext context)
	{
	var response = context.HttpContext.Response;
	
	// 配置CSP:只允许加载本域名的脚本、样式,禁止内联脚本和eval
	response.Headers.Add(
	"Content-Security-Policy",
	"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;");
	
	// 其他安全头:防止点击劫持
	response.Headers.Add("X-Frame-Options", "DENY");
	// 防止MIME类型嗅探
	response.Headers.Add("X-Content-Type-Options", "nosniff");
	// 启用XSS保护
	response.Headers.Add("X-XSS-Protection", "1; mode=block");
	}
	}

代码逐行讲解:
1.Content-Security-Policy:
1.default-src 'self':默认只允许加载本域名的资源;
2.script-src 'self':只允许加载本域名的脚本,禁止内联脚本和第三方脚本;
3.style-src 'self' 'unsafe-inline':允许本域名的样式,允许内联样式(因为很多前端框架用内联样式);
4.img-src 'self' data::允许本域名的图片和base64图片;
2.X-Frame-Options:禁止页面被嵌入到iframe中,防止点击劫持;
3.X-Content-Type-Options:禁止浏览器嗅探MIME类型,防止把文本当成脚本执行;
4.X-XSS-Protection:启用浏览器的XSS保护,发现XSS时阻止页面加载。
拓展知识:前端防XSS的方法
1.用textContent代替innerHTML渲染用户输入;
2.用DOMPurify过滤用户输入的HTML(如果必须允许HTML);
3.不要信任用户输入的任何内容,包括URL、Cookie、LocalStorage;
4.用HttpOnly Cookie:Cookie设置HttpOnly属性,JavaScript无法读取,防止被XSS窃取。
最佳实践:
1.输出编码:所有用户输入的内容都要进行HTML编码;
2.输入验证:限制用户输入的格式、长度;
3.启用CSP:作为最后一道防线,即使编码被绕过,CSP也能阻止恶意脚本执行;
4.用HttpOnly Cookie:防止Cookie被XSS窃取;
5.定期扫描:用OWASP ZAP等工具扫描网站,发现XSS漏洞。
四、DDoS攻击:网站被流量淹没,用限流和CDN防
DDoS(分布式拒绝服务攻击)**是黑客用大量僵尸机发送请求,让服务器资源耗尽,网站无法正常访问——比如黑客用1000台电脑同时访问你的网站,服务器CPU、内存、带宽被占满,正常用户无法访问。
核心原理(大白话)
黑客用大量请求淹没服务器,服务器处理不过来,导致正常用户的请求无法被处理。DDoS分三种类型:
1.流量型DDoS:发送大量UDP、TCP数据包,占满带宽(比如SYN洪水攻击);
2.协议型DDoS:利用协议漏洞,发送大量半连接请求,占满服务器连接数(比如SYN洪水);
3.应用层DDoS:发送大量合法的HTTP请求,占满服务器CPU、内存(比如大量登录请求、API请求)。
实战3:用ASP.NET Core防应用层DDoS(限流)
对于应用层DDoS,用限流中间件限制每个IP的请求次数:
csharp

	// Program.cs
	using Microsoft.AspNetCore.RateLimiting;
	using System.Threading.RateLimiting;
	
	var builder = WebApplication.CreateBuilder(args);
	
	// 添加限流服务
	builder.Services.AddRateLimiter(options =>
	{
	// 固定窗口限流:每个IP每分钟最多100次请求
	options.AddFixedWindowLimiter(policyName: "fixed", options =>
	{
	options.Window = TimeSpan.FromMinutes(1);
	options.PermitLimit = 100;
	options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
	options.QueueLimit = 10; // 超过限流后,最多排队10个请求
	});
	
	// 全局限流:整个服务器每分钟最多10000次请求
	options.AddFixedWindowLimiter(policyName: "global", options =>
	{
	options.Window = TimeSpan.FromMinutes(1);
	options.PermitLimit = 10000;
	});
	
	// 拒绝请求时返回429 Too Many Requests
	options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
	});
	
	builder.Services.AddControllersWithViews();
	
	var app = builder.Build();
	
	// 启用限流
	app.UseRateLimiter();
	
	// 其他中间件
	app.UseHttpsRedirection();
	app.UseStaticFiles();
	app.UseRouting();
	app.UseAuthorization();
	
	// 给API控制器应用限流策略
	app.MapControllerRoute(
	name: "default",
	pattern: "{controller=Home}/{action=Index}/{id?}")
	.RequireRateLimiting("fixed"); // 每个IP每分钟最多100次请求
	
	// 给全局应用限流策略
	app.Map("/api/global", () => Results.Ok("Global API"))
	.RequireRateLimiting("global");
	
	app.Run();

代码逐行讲解:
1.AddFixedWindowLimiter:固定窗口限流,比如每个IP每分钟最多100次请求;
1.Window:窗口时间(1分钟);
2.PermitLimit:窗口内的最大请求次数(100);
3.QueueLimit:超过限流后,最多排队10个请求,超过的请求返回429;
2.UseRateLimiter:启用限流中间件;
3.RequireRateLimiting:给路由应用限流策略,比如给API控制器应用“fixed”策略,给全局API应用“global”策略;
4.RejectionStatusCode:拒绝请求时返回429状态码,告诉客户端请求太频繁。
我踩过的坑:一开始限流阈值设得太低,导致正常用户被限流,后来根据服务器性能调整阈值——限流阈值要根据服务器的CPU、内存、带宽来设置,比如服务器能处理1000QPS,就把全局限流设为10000次/分钟(约167QPS)。
实战4:用CDN和WAF防DDoS攻击
对于流量型和协议型DDoS,单靠服务器限流没用,必须用CDN和WAF(Web应用防火墙):
1.CDN:把静态资源缓存到CDN节点,用户请求先到CDN,CDN过滤掉恶意请求,正常请求转发到服务器;
2.WAF:比如阿里云WAF、Cloudflare WAF,过滤恶意请求(比如SQL注入、XSS、DDoS);
3.云DDoS高防:比如阿里云DDoS高防、腾讯云DDoS高防,清洗恶意流量,把正常流量转发到服务器。
拓展知识:DDoS攻击的应急处理
1.切换到CDN:把域名解析到CDN,让CDN清洗流量;
2.启用WAF:开启WAF的DDoS防护规则;
3.限流:临时降低限流阈值,减少服务器压力;
4.联系云服务商:如果攻击流量太大,联系云服务商开启紧急防护;
5.监控:用Prometheus、Grafana监控服务器的CPU、内存、带宽,及时发现攻击。
最佳实践:
1.用CDN:把静态资源、API请求放到CDN,减少服务器压力;
2.启用WAF:过滤恶意请求,防止SQL注入、XSS、DDoS;
3.限流:给API、登录等接口设置限流阈值;
4.冗余部署:把服务器部署到多个可用区,防止单点故障;
5.监控告警:设置CPU、内存、带宽的告警阈值,及时发现攻击。
五、总结:三种攻击的防御对比

 

攻击类型 核心原理 防御方法 最佳实践
SQL注入 恶意SQL被执行 参数化查询、ORM、最小权限、输入验证 永远用参数化查询,不要拼接SQL
XSS攻击 恶意HTML/JS被执行 输出编码、输入验证、CSP、HttpOnly Cookie 所有用户输入都要HTML编码,启用CSP
DDoS攻击 服务器被流量淹没 限流、CDN、WAF、云DDoS高防 用CDN和WAF,设置合理的限流阈值
 


防御体系的核心思想
防御网络攻击的核心是“多层防御”,不要依赖单一防御方法,比如防SQL注入要同时用参数化查询、输入验证、最小权限;防XSS要同时用输出编码、输入验证、CSP;防DDoS要同时用限流、CDN、WAF。
下一节我们会学习网络编程的性能测试与调优,让你的网站既安全又快。

 本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49553.html

	using System;
	using System.Data.SqlClient;
	
	namespace SqlInjectionDefense;
	
	class AdoNetExample
	{
	static void Main(string[] args)
	{
	// 黑客输入的恶意用户名
	string maliciousUsername = "' OR 1=1 --";
	string password = "anypassword";
	
	// 错误写法:拼接SQL,会被注入
	string badSql = $"SELECT COUNT(*) FROM Users WHERE Username='{maliciousUsername}' AND Password='{password}'";
	Console.WriteLine($"恶意SQL:{badSql}");
	// 执行这条SQL会返回所有用户,黑客登录成功
	
	// 正确写法:参数化查询,防止注入
	string goodSql = "SELECT COUNT(*) FROM Users WHERE Username=@Username AND Password=@Password";
	string connectionString = "Server=.;Database=DemoDB;Trusted_Connection=True;";
	
	using (var conn = new SqlConnection(connectionString))
	{
	conn.Open();
	using (var cmd = new SqlCommand(goodSql, conn))
	{
	// 添加参数,SQL Server会自动处理转义,防止注入
	cmd.Parameters.AddWithValue("@Username", maliciousUsername);
	cmd.Parameters.AddWithValue("@Password", password);
	
	int count = (int)cmd.ExecuteScalar();
	Console.WriteLine($"参数化查询结果:{count}(0表示登录失败,正确防御了注入)");
	}
	}
	}
	}

代码逐行讲解:
1.拼接SQL的问题:恶意输入会被当成SQL语句的一部分执行,导致注入;
2.参数化查询:用@Username代替直接拼接,SQL Server会把参数当成数据,而不是SQL语句的一部分,自动处理转义(比如把'转成''),防止注入;
3.AddWithValue:添加参数,参数值会被安全地传递给SQL Server,不会被解析成SQL语句。
我踩过的坑:一开始用存储过程,以为存储过程能防注入,结果在存储过程里用了EXEC('SELECT * FROM Users WHERE Username=' + @Username),还是被注入了——存储过程如果用动态SQL拼接,同样会被注入,必须用参数化!
实战2:用EF Core防SQL注入(ORM的优势)
EF Core的LINQ查询默认是参数化的,自动防注入:
csharp

	using System;
	using System.Linq;
	using Microsoft.EntityFrameworkCore;
	
	namespace EFCoreExample;
	
	public class User
	{
	public int Id { get; set; }
	public string Username { get; set; }
	public string Password { get; set; }
	}
	
	public class AppDbContext : DbContext
	{
	public DbSet<User> Users { get; set; }
	
	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
	{
	optionsBuilder.UseSqlServer("Server=.;Database=DemoDB;Trusted_Connection=True;");
	}
	}
	
	class EFCoreDefense
	{
	static void Main(string[] args)
	{
	string maliciousUsername = "' OR 1=1 --";
	string password = "anypassword";
	
	using (var db = new AppDbContext())
	{
	// LINQ查询自动参数化,防注入
	var user = db.Users.FirstOrDefault(u => u.Username == maliciousUsername && u.Password == password);
	Console.WriteLine($"EF Core查询结果:{(user == null ? "登录失败" : "登录成功")}");
	
	// 注意:如果用FromSqlRaw拼接SQL,同样会被注入,必须用参数化
	// 错误写法:db.Users.FromSqlRaw($"SELECT * FROM Users WHERE Username='{maliciousUsername}'");
	// 正确写法:db.Users.FromSqlRaw("SELECT * FROM Users WHERE Username=@Username", new SqlParameter("@Username", maliciousUsername));
	}
	}
	}

代码逐行讲解:
1.LINQ查询:EF Core会把LINQ转换成参数化SQL,自动防注入,比如u.Username == maliciousUsername会被转换成@p0参数;
2.FromSqlRaw的注意事项:如果必须用原生SQL,一定要用参数化,不能拼接,否则会被注入;
3.ORM的优势:大部分ORM(EF Core、Dapper)都默认支持参数化查询,能有效防止SQL注入,推荐使用ORM,减少手动拼接SQL的机会。
拓展知识:SQL注入的变种
1.盲注:如果网站没有返回错误信息,黑客用AND 1=1、AND 1=0判断SQL是否执行成功,慢慢猜数据库内容;
2.时间盲注:用WAITFOR DELAY '0:0:5',通过响应时间判断SQL是否执行成功;
3.报错注入:用CAST((SELECT Username FROM Users LIMIT 1) AS INT),通过错误信息获取数据库内容。
最佳实践:
1.永远用参数化查询,不要拼接SQL;
2.用ORM代替手动写SQL;
3.最小权限原则:数据库用户只给必要的权限(比如SELECT、INSERT),不要给SA权限;
4.输入验证:限制用户输入的长度、格式(比如用户名只能是字母和数字);
5.输出编码:如果必须显示用户输入的SQL结果,要进行HTML编码,防止XSS。
三、XSS攻击:用户输入的HTML被执行,用编码就能防
XSS(跨站脚本攻击)是黑客在用户输入中插入恶意HTML/JavaScript,当其他用户访问时,恶意脚本被执行——比如黑客在论坛发帖子,内容是,如果网站没过滤,其他用户打开帖子时会弹出alert,甚至被窃取Cookie,账号被盗。
核心原理(大白话)
网站把用户输入的内容直接显示在页面上,没有过滤HTML标签,导致恶意脚本被浏览器执行。比如:
csharp

	string userInput = "<script>alert('XSS')</script>";
	Response.Write($"用户评论:{userInput}");

浏览器会执行);
2.存储型XSS:恶意脚本被存储在数据库中,其他用户访问时执行(比如论坛帖子、评论);
3.DOM型XSS:恶意脚本通过修改页面DOM执行,不需要服务器参与(比如前端用innerHTML渲染用户输入)。
实战2:用ASP.NET Core防XSS攻击

  1. 输入验证与输出编码(服务器端)
    csharp
	using Microsoft.AspNetCore.Mvc;
	using System.Text.Encodings.Web;
	using System.Text.RegularExpressions;
	
	namespace XssDefense.Controllers;
	
	public class HomeController : Controller
	{
	private readonly HtmlEncoder _htmlEncoder;
	
	// 注入HtmlEncoder,用于HTML编码
	public HomeController(HtmlEncoder htmlEncoder)
	{
	_htmlEncoder = htmlEncoder;
	}
	
	// 反射型XSS防御:输出编码
	public IActionResult Search(string keyword)
	{
	// 错误写法:直接输出用户输入,会被XSS
	// ViewData["Result"] = $"搜索结果:{keyword}";
	
	// 正确写法:HTML编码,把<转成&lt;,>转成&gt;,脚本不会被执行
	string encodedKeyword = _htmlEncoder.Encode(keyword);
	ViewData["Result"] = $"搜索结果:{encodedKeyword}";
	return View();
	}
	
	// 存储型XSS防御:输入验证+输出编码
	[HttpPost]
	public IActionResult PostComment(string comment)
	{
	// 输入验证:禁止HTML标签
	if (Regex.IsMatch(comment, @"<[^>]+>"))
	{
	ModelState.AddModelError("comment", "评论不能包含HTML标签");
	return View();
	}
	
	// 存储到数据库(这里省略存储逻辑)
	// db.Comments.Add(new Comment { Content = comment });
	// db.SaveChanges();
	
	// 输出编码:即使输入验证被绕过,编码也能防止XSS
	string encodedComment = _htmlEncoder.Encode(comment);
	ViewData["Comment"] = $"你的评论:{encodedComment}";
	return View();
	}
	}

代码逐行讲解:
1.HtmlEncoder.Encode:把HTML特殊字符转成实体编码,比如<转成&lt;,>转成&gt;,这样浏览器会把<script>当成普通文本显示,不会执行;
2.输入验证:用正则表达式禁止HTML标签,作为第一道防线,即使编码被绕过,输入验证也能拦截;
3.双重防御:输入验证+输出编码,是防XSS的黄金组合——不要只依赖输入验证,因为黑客可以用编码绕过(比如<script>),输出编码是最后一道防线。
我踩过的坑:一开始用正则表达式过滤HTML标签,以为能防所有XSS,结果黑客用javascript:alert('XSS')作为链接,还是被执行了——输入验证不能覆盖所有情况,输出编码才是最可靠的!
2. 用CSP(内容安全策略)防XSS(浏览器端)
CSP是浏览器的安全机制,限制页面加载的资源(比如脚本、样式、图片),防止恶意脚本执行。在ASP.NET Core中配置CSP:
csharp

	// Program.cs
	builder.Services.AddControllersWithViews(options =>
	{
	options.Filters.Add(new SecurityHeadersAttribute());
	});
	
	// 自定义安全头过滤器
	public class SecurityHeadersAttribute : ActionFilterAttribute
	{
	public override void OnResultExecuting(ResultExecutingContext context)
	{
	var response = context.HttpContext.Response;
	
	// 配置CSP:只允许加载本域名的脚本、样式,禁止内联脚本和eval
	response.Headers.Add(
	"Content-Security-Policy",
	"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;");
	
	// 其他安全头:防止点击劫持
	response.Headers.Add("X-Frame-Options", "DENY");
	// 防止MIME类型嗅探
	response.Headers.Add("X-Content-Type-Options", "nosniff");
	// 启用XSS保护
	response.Headers.Add("X-XSS-Protection", "1; mode=block");
	}
	}

代码逐行讲解:
1.Content-Security-Policy:
1.default-src 'self':默认只允许加载本域名的资源;
2.script-src 'self':只允许加载本域名的脚本,禁止内联脚本和第三方脚本;
3.style-src 'self' 'unsafe-inline':允许本域名的样式,允许内联样式(因为很多前端框架用内联样式);
4.img-src 'self' data::允许本域名的图片和base64图片;
2.X-Frame-Options:禁止页面被嵌入到iframe中,防止点击劫持;
3.X-Content-Type-Options:禁止浏览器嗅探MIME类型,防止把文本当成脚本执行;
4.X-XSS-Protection:启用浏览器的XSS保护,发现XSS时阻止页面加载。
拓展知识:前端防XSS的方法
1.用textContent代替innerHTML渲染用户输入;
2.用DOMPurify过滤用户输入的HTML(如果必须允许HTML);
3.不要信任用户输入的任何内容,包括URL、Cookie、LocalStorage;
4.用HttpOnly Cookie:Cookie设置HttpOnly属性,JavaScript无法读取,防止被XSS窃取。
最佳实践:
1.输出编码:所有用户输入的内容都要进行HTML编码;
2.输入验证:限制用户输入的格式、长度;
3.启用CSP:作为最后一道防线,即使编码被绕过,CSP也能阻止恶意脚本执行;
4.用HttpOnly Cookie:防止Cookie被XSS窃取;
5.定期扫描:用OWASP ZAP等工具扫描网站,发现XSS漏洞。
四、DDoS攻击:网站被流量淹没,用限流和CDN防
DDoS(分布式拒绝服务攻击)**是黑客用大量僵尸机发送请求,让服务器资源耗尽,网站无法正常访问——比如黑客用1000台电脑同时访问你的网站,服务器CPU、内存、带宽被占满,正常用户无法访问。
核心原理(大白话)
黑客用大量请求淹没服务器,服务器处理不过来,导致正常用户的请求无法被处理。DDoS分三种类型:
1.流量型DDoS:发送大量UDP、TCP数据包,占满带宽(比如SYN洪水攻击);
2.协议型DDoS:利用协议漏洞,发送大量半连接请求,占满服务器连接数(比如SYN洪水);
3.应用层DDoS:发送大量合法的HTTP请求,占满服务器CPU、内存(比如大量登录请求、API请求)。
实战3:用ASP.NET Core防应用层DDoS(限流)
对于应用层DDoS,用限流中间件限制每个IP的请求次数:
csharp

	// Program.cs
	using Microsoft.AspNetCore.RateLimiting;
	using System.Threading.RateLimiting;
	
	var builder = WebApplication.CreateBuilder(args);
	
	// 添加限流服务
	builder.Services.AddRateLimiter(options =>
	{
	// 固定窗口限流:每个IP每分钟最多100次请求
	options.AddFixedWindowLimiter(policyName: "fixed", options =>
	{
	options.Window = TimeSpan.FromMinutes(1);
	options.PermitLimit = 100;
	options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
	options.QueueLimit = 10; // 超过限流后,最多排队10个请求
	});
	
	// 全局限流:整个服务器每分钟最多10000次请求
	options.AddFixedWindowLimiter(policyName: "global", options =>
	{
	options.Window = TimeSpan.FromMinutes(1);
	options.PermitLimit = 10000;
	});
	
	// 拒绝请求时返回429 Too Many Requests
	options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
	});
	
	builder.Services.AddControllersWithViews();
	
	var app = builder.Build();
	
	// 启用限流
	app.UseRateLimiter();
	
	// 其他中间件
	app.UseHttpsRedirection();
	app.UseStaticFiles();
	app.UseRouting();
	app.UseAuthorization();
	
	// 给API控制器应用限流策略
	app.MapControllerRoute(
	name: "default",
	pattern: "{controller=Home}/{action=Index}/{id?}")
	.RequireRateLimiting("fixed"); // 每个IP每分钟最多100次请求
	
	// 给全局应用限流策略
	app.Map("/api/global", () => Results.Ok("Global API"))
	.RequireRateLimiting("global");
	
	app.Run();

代码逐行讲解:
1.AddFixedWindowLimiter:固定窗口限流,比如每个IP每分钟最多100次请求;
1.Window:窗口时间(1分钟);
2.PermitLimit:窗口内的最大请求次数(100);
3.QueueLimit:超过限流后,最多排队10个请求,超过的请求返回429;
2.UseRateLimiter:启用限流中间件;
3.RequireRateLimiting:给路由应用限流策略,比如给API控制器应用“fixed”策略,给全局API应用“global”策略;
4.RejectionStatusCode:拒绝请求时返回429状态码,告诉客户端请求太频繁。
我踩过的坑:一开始限流阈值设得太低,导致正常用户被限流,后来根据服务器性能调整阈值——限流阈值要根据服务器的CPU、内存、带宽来设置,比如服务器能处理1000QPS,就把全局限流设为10000次/分钟(约167QPS)。
实战4:用CDN和WAF防DDoS攻击
对于流量型和协议型DDoS,单靠服务器限流没用,必须用CDN和WAF(Web应用防火墙):
1.CDN:把静态资源缓存到CDN节点,用户请求先到CDN,CDN过滤掉恶意请求,正常请求转发到服务器;
2.WAF:比如阿里云WAF、Cloudflare WAF,过滤恶意请求(比如SQL注入、XSS、DDoS);
3.云DDoS高防:比如阿里云DDoS高防、腾讯云DDoS高防,清洗恶意流量,把正常流量转发到服务器。
拓展知识:DDoS攻击的应急处理
1.切换到CDN:把域名解析到CDN,让CDN清洗流量;
2.启用WAF:开启WAF的DDoS防护规则;
3.限流:临时降低限流阈值,减少服务器压力;
4.联系云服务商:如果攻击流量太大,联系云服务商开启紧急防护;
5.监控:用Prometheus、Grafana监控服务器的CPU、内存、带宽,及时发现攻击。
最佳实践:
1.用CDN:把静态资源、API请求放到CDN,减少服务器压力;
2.启用WAF:过滤恶意请求,防止SQL注入、XSS、DDoS;
3.限流:给API、登录等接口设置限流阈值;
4.冗余部署:把服务器部署到多个可用区,防止单点故障;
5.监控告警:设置CPU、内存、带宽的告警阈值,及时发现攻击。
五、总结:三种攻击的防御对比
 

攻击类型 核心原理 防御方法 最佳实践
SQL注入 恶意SQL被执行 参数化查询、ORM、最小权限、输入验证 永远用参数化查询,不要拼接SQL
XSS攻击 恶意HTML/JS被执行 输出编码、输入验证、CSP、HttpOnly Cookie 所有用户输入都要HTML编码,启用CSP
DDoS攻击 服务器被流量淹没 限流、CDN、WAF、云DDoS高防 用CDN和WAF,设置合理的限流阈值
 

防御体系的核心思想
防御网络攻击的核心是“多层防御”,不要依赖单一防御方法,比如防SQL注入要同时用参数化查询、输入验证、最小权限;防XSS要同时用输出编码、输入验证、CSP;防DDoS要同时用限流、CDN、WAF。
下一节我们会学习网络编程的性能测试与调优,让你的网站既安全又快。

 本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49553.html



相关教程