黑客尝试攻破一个 Web 应用程序时,他们通常首先跟随每个链接来找到所有有效的路径,以筹划攻击。然后,他们尝试在输入字段中输入各种无效的值,查看应用程序是否存在任何已知的代码注入漏洞。在本教程中,您将学习如何检测这些攻击。检测到它们后,您可关闭来自攻击 IP 地址的访问,将它重定向到一个缓慢的或执行其他操作来变成难以被攻击的目标。
全新的 developerWorks Premium 会员计划提供了强大的开发工具和资源,包括 500 篇通过 Safari Books Online 提供的顶级技术文章(50 多篇是专门针对安全性开发人员的),最重要开发人员活动的大幅折扣,最近的 O'Reilly 大会的视频回放,等等。立即注册。
运行应用程序
获取代码
“ 在本教程中,学习在您的 IBM Bluemix Node.js web 应用程序被扫描和攻击时如何检测出来。 ”
这个应用程序包含一个主页,其中包含一个登录表单。在表单的顶部,有一些按钮用于方便发出各种攻击。这些按钮下面是向 cookie 中放入危险值的按钮。在页面的底部,显示了在前 1 个小时内检测到的所有攻击的列表。请注意,该应用程序报告的时间为 UTC ,不是您当地的时间。
点击查看大图
关闭 [x]
本文中演示的技术可检测 4 种类型的攻击:
可按如下方式发出任何这些攻击:
现在您已看到检测到的攻击,让我们看看代码,了解它是如何完成的。
第一步是检测访问各种无效页面的尝试。这将检测映射尝试,这些尝试通常是攻击的前奏。
Express 应用程序包 让此步骤变得非常容易。在 Express 中,可注册路径的处理函数,这些处理函数可完整地处理请求,或者执行部分处理(例如解析请求中的 cookie)并让请求流程继续运行。处理函数按声明它们的顺序处理。
要获得所有没有附加页面的请求,只需在末尾注册一个处理函数。如果已有一个返回 404 page unavailable
错误的默认处理函数,则将攻击检测代码添加到该处理函数。
app.use("/", function(req, res) { res.send("Attempt to access " + req.path + " duly noted." + goBack); logBadPathAttack(req); });
备注: 不是所有映射尝试都是恶意的。搜索引擎通常会映射网站,以便能够链接到它们的各个页面。可使用一个 robots.txt 文件来让合法的搜索引擎跳过您的网站。
攻击者不会尝试访问每个可能的路径,因为这种路径太多了。即使限制到仅包含字母和 8 个字符,也有 26^8≈2·10^11 种可能性。如果攻击者可在一秒内发送 10,000 个请求,仍需要超过 230 天才能检查完所有请求。
黑客会扫描他们合法地从应用程序获取的网页,寻找 URL 来找到他们可扫描的其他内容。为了促使他们扫描无效的页面,可放入合法用户绝不会看到的 HTML 代码链接。
例如,可使用以不可见的形式呈现链接的代码:
<a href="should_be_invisible.html" style="color: white; background-color: white">Invisible</a>
如果使用 Angular 框架来执行客户端编程,可使用 ng-if
指定绝不会对无效的链接发生的条件。这些条件的优势是扫描器很难评估它们。例如,如果不跟踪所有范围变量,扫描器就不会知道有一个名为 no-such-var
的变量,进而也不会知道该变量的值绝不是 'hello'
。
<div ng-if="false"> <a href="index_false.html">Don't go here</a>. </div> <a href="index_1_is_2.html" ng-if="1==2"">Link to nowhere.</a> <a href="index_complex_false.html" ng-if="no-such-var == 'hello'">Another useless link.</a>
许多攻击都依赖于提供无效的值。例如,一种 SQL 注入 依靠使用 SQL 字符串终止符 '
,后跟 " or
"(表示始终为 true 的条件,比如 correctPassword='<input value>' or 1=1
)、" and
"(表示始终为 false 的条件,比如 <condition> and 1=0
)或一个分号(表示一个批处理命令,就像在这个 XKCD 动画 中一样)。
这是检测这些攻击的方式:
// Regular expressions that indicate attacks var inputAttacks = [ { title: "SQL Batch Injection", regex: /'.*;/}, { title: "SQL Or Injection", regex: /'.*or/i}, { title: "SQL And Injection", regex: /'.*and/i}, { title: "File Inclusion", regex: //././//}, { title: "File Inclusion", regex: /^///} ];
// Check all the body parameters for validity app.use("/", function(req, res, next) { var key; // Check all GET queries for (key in req.query) checkInputAttacks("query parameter " + key, req.query[key], req, res); // Check all POST data for (key in req.body) checkInputAttacks("post parameter " + key, req.body[key], req, res); // Check all cookies for (key in req.cookies) checkInputAttacks("cookie " + key, req.cookies[key], req, res); // If we ran res.send (which checkInputAttacks does when it detects an attack), // next() won't continue the processing anyway. next(); });
// Check for attacks in a string we got from the user. var checkInputAttacks = function(location, str, req, res) { for(var i=0; i<inputAttacks.length; i++) if (str.match(inputAttacks[i].regex)) { logBadInputAttack(req, str, inputAttacks[i].title + " in the " + location); res.send("Your " + inputAttacks[i].title + " attack in the " + location + " has been noted." + goBack); } };
// Log a bad input attack var logBadInputAttack = function(req, str, title) { var entry = {}; entry.timeStamp = new Date(); entry.title = "Bad input: " + title; entry.target = req.originalUrl; entry.value = str; entry.attacker = req.ip; loggedAttacks.push(entry); };
注意此方法可能发生误报。例如,想象一个用户在描述字段中键入以下信息:“ This is the user's choice; the user can either apply this feature or ignore it
”
该文本与一种 SQL 批处理攻击的正则表达式匹配:一个撇号 (') 后跟许多字符,这些字符用分号 (;) 隔开。如果有必要,可以指定对于一些路径,不检查一些字段。req 对象包含该路径。要从检查中排除一些字段,可创建豁免字段的列表(涵盖所有 3 种类型:get 参数、post 参数和 cookie):
// Fields that are not checked for the three field types var exemptGet = []; var exemptPost = ["/login:exempt"]; var exemptCookie = [];
修改检查这些字段的调用,以首先检查它们是否在适用的豁免列表中,如果是,则不检查它们:
// Check all the body parameters for validity app.use("/", function(req, res, next) { var key; // Check all GET queries for (key in req.query) if (exemptGet.indexOf(req.path + ":" + key) === -1) // Don't check exempt fields checkInputAttacks('query parameter "' + key + '"', req.query[key], req, res); // Check all POST data for (key in req.body) if (exemptPost.indexOf(req.path + ":" + key) === -1) // Don't check exempt fields checkInputAttacks('post parameter "' + key + '"', req.body[key], req, res); // Check all cookies for (key in req.cookies) if (exemptCookie.indexOf(req.path + ":" + key) === -1) // Don't check exempt fields checkInputAttacks('cookie "' + key + '"', req.cookies[key], req, res); // If we ran res.send (which checkInputAttacks does when it detects an attack), // next() won't continue the processing anyway. next(); });
IBM Bluemix 包含一个 AppScan 服务,该服务在您的应用程序上运行各种攻击来识别它的漏洞。要确认攻击已记录,可以对您的应用程序运行它(参阅 “ 将 Bluemix AppScan 结果放入 Bluemix Track & Plan 中 ” 中的第 3 步)。在下表中,可以看到一些结果。甚至这个微型 Web 应用程序也检测到 AppScan 的 364 次不同的攻击尝试。
类型 | 时间 | 攻击 IP | 路径 |
---|---|---|---|
无效路径 | 2015-11-27T03:43:03.481Z | 174.37.31.187 | /badPath.html |
无效路径 | 2015-11-27T03:43:03.493Z | 174.37.31.187 | /index_1_is_2.html |
错误输入:查询参数 "uid" 中的 SQL Batch 注入 | 2015-11-27T03:43:03.496Z | 174.37.31.187 | /login?uid=%27+or+true%3B+--&passwd=' or true; -- |
错误输入:查询参数 "uid" 中的 SQL Or 注入 | 2015-11-27T03:43:03.496Z | 174.37.31.187 | /login?uid=%27+or+true%3B+--&passwd=' or true; -- |
无效路径 | 2015-11-27T03:43:03.524Z | 174.37.31.187 | /NonExistentFile |
错误输入:查询参数 "uid" 中的 SQL Batch 注入 | 2015-11-27T03:43:03.525Z | 174.37.31.187 | /login?uid=%27+or+ |
现在您已知道如何检测攻击。检测到攻击后,您可 将它报告给 Track & Plan ,拦截来自该 IP 地址的访问,或者执行其他步骤来让攻击更困难。
相关主题: MEAN Eclipse Bluemix