Close to the cnode community, an article about XSS by @ Wu ZhonghuaArticle, Directly causing the community to start trying various attacks on cnode. Here we summarize some of the problems and solutions encountered this time. File Upload Vulnerability
The logic for nodeclub to upload images is as follows:
// User-uploaded file name var filename = Date. now () + '_' + file. name; // user folder var userDir = path. join (config. upload_dir, uid); // path of the final file storage var savepath = path. join (userDir, filename); // move the File Uploaded by the user from the temporary directory to the final save path fs. rename (file. path, savepath, callback );
It seems that there is no problem. Each uploaded file is stored in a folder named after the user UID and prefixed with the current timestamp. However, when a user maliciously constructs the input, the problem arises. When a user uploads a fileFilenameIs/../XxxThe uploaded file will be rename outside the user folder, so that the user can replace any file on the existing system.
This vulnerability is relatively low-level, but has the most serious consequences. It directly causes the entire system to be controlled by users. The solution is also simple:
Var filename = Date. now () + '_' + file. name; var userDir = path. join (config. upload_dir, uid); // obtain the absolute path var savepath = path. resolve (path. join (userDir, filename); // verify if (savepath. indexOf (path. resolve (userDir ))! = 0) {return res. send ({status: 'foridden '});} fs. rename (file. path, savepath, callback );
XSS of Rich Text Editor
XSS has been described in detail in @ Wu Zhonghua's article. In the cnode community, users can post and reply to topics.MarkdownFormat Rich Text Editor. No XSS preventive measures have been taken before, so you can directly write:
<script>alert(123);</script><div onmouseover="alert(123)"></div><a href="javascript:alert(123);">123</a>
The content in markdown format does not have URL validity detection, so the XSS of various styles came out again:
[xss][1][xss][2]![xss][3][1]: javascript:alert(123);[2]: http://www.baidu.com/#"onclick='alert(123)'[3]: http://www.baidu.com/img.jpg#"onmouseover='alert(123)'
In this community Application Scenario, HTML tags are introduced only for typographical operations, while other style definitions only make the entire interface messy, not to mention the potential risks of XSS vulnerabilities. Therefore, we do not need to support HTML tags for content formatting. Everything can be replaced by markdown. Then, the XSS risk caused by directly inputting HTML can be eliminated through simple and crude HTML escape.
function escape(html) { return html.replace(/&(?!\w+;)/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"');}
However, such a rough escape may cause<>;These special characters are also escaped and cannot be correctly displayed. You need to extract and save the code segment and only escape the non-code segment. So thisEscapeThe function becomes like this:
function escape(html) { var codeSpan = /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm; var codeBlock = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g; var spans = []; var blocks = []; var text = String(html).replace(/\r\n/g, '\n') .replace('/\r/g', '\n'); text = '\n\n' + text + '\n\n'; text = text.replace(codeSpan, function(code) { spans.push(code); return '`span`'; }); text += '~0'; return text.replace(codeBlock, function (whole, code, nextChar) { blocks.push(code); return '\n\tblock' + nextChar; }) .replace(/&(?!\w+;)/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/`span`/g, function() { return spans.shift(); }) .replace(/\n\tblock/g, function() { return blocks.shift(); }) .replace(/~0$/,'') .replace(/^\n\n/, '') .replace(/\n\n$/, '');};
For<A>Labels andThe href attribute in the tag must be checked for URL validity or xss filtering. This ensures that the HTML code generated through markdown does not have the XSS vulnerability.
Because XSS has many methods, see XSS Filter Evasion Cheat Sheet. Therefore, HTML escape is the safest, but not every place can use markdown to replace HTML code. Therefore, not every place can use HTML escape, in this case, other methods are required to filter out XSS vulnerabilities.
XSS protection can only be implemented by defining a whitelist. For example, only allow<P> <div> <a>Label, only allowHref class styleAttribute. Then, filter each attribute that may cause XSS.
The existing XSS filter module is node-validator and js-xss written by @ Lei zongmin.
The XSS module cannot prevent arbitrary XSS attacks, but at least it can filter out most of the vulnerabilities that can be imagined. Node-validator'sXSS ()There are still bugs.<P on = "> </p>Code in the form of double quotation marks, leading to HTML element leakage.
XSS attacks caused by the template engine
The cnode community uses ejs as the template engine. In ejs, two methods are provided to output dynamic data to the page:
<% = Data %> // output for xss filtering <%-data %> // output directly without Filtering
All filters must have one premise:The values of HTML attributes in the template file must use double quotation marks.. For example
' title='<%= reply.author.name %>' />
The first sentence of the preceding two statements uses single quotes. You can constructAvatar_urlWith single quotation marks to intercept the src attribute. javascript code can be added at will.
CSRF attack
Web development framework for CSRF attacks in nodeConnectAndExpressAnd so on. Store a random_ CsrfField. When the template engine generates an HTML file_ CsrfThe value is passed to the front-end. Any POST request submitted by the visitor must carry this field for verification, ensuring that only the current user can modify the current page.
However, when the page has an XSS vulnerability, the CSRF prevention measures become a cloud. Attackers can use javascript code to obtain_ CsrfAnd directly simulate the user's POST request to change the server data.