Javascript 用HTML等价物替换字符串。除了<;a>;标签

Javascript 用HTML等价物替换字符串。除了<;a>;标签,javascript,jquery,regex,code-injection,Javascript,Jquery,Regex,Code Injection,如何替换字符串: Hello my name is <a href='/max'>max</a>! <script>alert("DANGEROUS SCRIPT INJECTION");</script> 但是我仍然希望能够有链接 我还研究了通过以下方式防止脚本注入: var html = $(string.bold()); html.find('script').remove(); 但是我希望仍然能够读取脚本标记,而不是将其删除。解决

如何替换
字符串

Hello my name is <a href='/max'>max</a>! 
<script>alert("DANGEROUS SCRIPT INJECTION");</script>
但是我仍然希望能够有
链接


我还研究了通过以下方式防止脚本注入:

var html = $(string.bold()); 
html.find('script').remove();

但是我希望仍然能够读取脚本标记,而不是将其删除。

解决此问题的一种方法是使用带有严格的查找模式的正则表达式,该模式只允许非常接近某一格式的锚

假设您只希望允许符合以下示例的链接:

<a href="http://host.domain/path?query#anchor">text</a>
也许其他人对这个子问题有更好的解决方案

这是最后一个字符串。替换:

string.replace(/<(?!a href="https?:\/\/\w[\w.-\/\?#]+">\w+<\/a>|\/a>)/g, '&lt;');
string.replace(/\w+\/a>)/g';

注意:所有这些输入检查必须始终在服务器端进行,在客户端,检查可以简单地绕过,并且尽管进行了检查,您仍会将恶意数据发送到服务器。

此代码段应该可以做到这一点。您可以在数组
allowedTagNames
中添加希望作为HTML标记传递的其他标记名

// input
var html = "Hello my name is <a href='/max'>max</a>! <script>alert('DANGEROUS SCRIPT INJECTION');</script>";

var allowedTagNames = ["a"];
// output
var processedHTML = "";

var processingStart = 0;
// this block finds the next tag and processes it
while (true) {
    var tagStart = html.indexOf("<", processingStart);
    if (tagStart === -1) { break; }

    var tagEnd = html.indexOf(">", tagStart);
    if (tagEnd === -1) { break; }

    var tagNameStart = tagStart + 1;
    if (html[tagNameStart] === "/") {
        // for closing tags
        ++tagNameStart;
    }
    // we expect there to be either a whitespace or a > after the tagName
    var tagNameEnd = html.indexOf(" ", tagNameStart);
    if (tagNameEnd === -1 || tagNameEnd > tagEnd) {
        tagNameEnd = tagEnd;
    }

    var tagName = html.slice(tagNameStart, tagNameEnd);
    // copy in text which is between this tag and the end of last tag
    processedHTML += html.slice(processingStart, tagStart);
    if (allowedTagNames.indexOf(tagName) === -1) {
        processedHTML += "&lt;" + html.slice(tagStart + 1, tagEnd) + "&gt;";
    } else {
        processedHTML += html.slice(tagStart, tagEnd + 1);
    }
    processingStart = tagEnd + 1;
}
// copy the rest of input which wasn't processed
processedHTML += html.slice(processingStart);
//输入
var html=“你好,我的名字是!alert(‘危险的脚本注入’);”;
var allowedTagNames=[“a”];
//输出
var processedHTML=“”;
var processingStart=0;
//此块查找下一个标记并对其进行处理
while(true){
var tagStart=html.indexOf(“,tagStart”);
如果(tagEnd==-1){break;}
var tagNameStart=tagStart+1;
如果(html[标记名开始]=“/”){
//用于结束标记
++tagNameStart;
}
//我们希望标记名后面有一个空格或>
var tagNameEnd=html.indexOf(“,tagNameStart”);
如果(tagNameEnd==-1 | | tagNameEnd>tagEnd){
tagNameEnd=tagEnd;
}
var tagName=html.slice(标记名开始,标记名结束);
//复制位于此标记和最后一个标记末尾之间的文本
processedHTML+=html.slice(processingStart,tagStart);
if(allowedTagNames.indexOf(标记名)=-1){
processedHTML+=“”+html.slice(tagStart+1,tagEnd)+“”;
}否则{
processedHTML+=html.slice(tagStart、tagEnd+1);
}
processingStart=tagEnd+1;
}
//复制未处理的其余输入
processedHTML+=html.slice(processingStart);
注意:如果标记的属性中有
,则它将不起作用。
例如:

您可以在Regex中使用捕获组和lookarounds来实现这一点

string = string.replace(/<((?!a )[^>]*)>/g, "&lt;$1&gt;").replace(/&lt;\/a&gt;/g, "</a>");
string=string.replace(/]*)>/g,“$1”)。replace(/\/a/g,”);

第一部分替换从
标记的所有HTML标记(锚定开始标记除外),第二部分替换所有更改的锚定结束标记()从
/a
返回到

如果您只想替换
,最好不要在字符串中使用任何HTML,并具有用于插入链接的预定义格式,与插入链接的方式类似(例如
[linktext](http://linkurl.com)
)。这样,字符串中就没有HTML,可以完全控制添加的内容。@RajaprabhuAravindasamy这不是重复的-它从字符串中删除所有HTML。OP希望保留
a
元素(可能还有其他元素),您可以使用
var newStr=$('',{html:str}).find(':not(a)').replaceWith(function(){return this.outerHTML.replace(//g,'').end().html()
其中
str
是原始字符串。也就是说,你肯定有更好的事情要做…@Maximilian,因为我认为这是一个错误,我相信你有更好的事情要做。如果我理解的话,您正在尝试在任何用户输入之后清理数据客户端。但是用户仍然可以发送他想要的任何东西。因此,如果您必须清理某些数据,则必须在服务器端而不是客户端完成。@A.Wolff提供的解决方案不完整,它将允许像
锚点这样的事情以及许多其他有问题的事情,如事件处理程序属性。这将无法防止恶意标记。考虑JavaScript:链接、事件处理程序属性等
<(?!a href="https?:\/\/\w[\w.-\/\?#]+">\w+<\/a>)
<(?!a href="https?:\/\/\w[\w.-\/\?#]+">\w+<\/a>|\/a>)
string.replace(/<(?!a href="https?:\/\/\w[\w.-\/\?#]+">\w+<\/a>|\/a>)/g, '&lt;');
// input
var html = "Hello my name is <a href='/max'>max</a>! <script>alert('DANGEROUS SCRIPT INJECTION');</script>";

var allowedTagNames = ["a"];
// output
var processedHTML = "";

var processingStart = 0;
// this block finds the next tag and processes it
while (true) {
    var tagStart = html.indexOf("<", processingStart);
    if (tagStart === -1) { break; }

    var tagEnd = html.indexOf(">", tagStart);
    if (tagEnd === -1) { break; }

    var tagNameStart = tagStart + 1;
    if (html[tagNameStart] === "/") {
        // for closing tags
        ++tagNameStart;
    }
    // we expect there to be either a whitespace or a > after the tagName
    var tagNameEnd = html.indexOf(" ", tagNameStart);
    if (tagNameEnd === -1 || tagNameEnd > tagEnd) {
        tagNameEnd = tagEnd;
    }

    var tagName = html.slice(tagNameStart, tagNameEnd);
    // copy in text which is between this tag and the end of last tag
    processedHTML += html.slice(processingStart, tagStart);
    if (allowedTagNames.indexOf(tagName) === -1) {
        processedHTML += "&lt;" + html.slice(tagStart + 1, tagEnd) + "&gt;";
    } else {
        processedHTML += html.slice(tagStart, tagEnd + 1);
    }
    processingStart = tagEnd + 1;
}
// copy the rest of input which wasn't processed
processedHTML += html.slice(processingStart);
string = string.replace(/<((?!a )[^>]*)>/g, "&lt;$1&gt;").replace(/&lt;\/a&gt;/g, "</a>");