views:

1915

answers:

7

Sometimes, server side will generate strings to be embedded in inline JavaScript code. For example, if "UserName" should be generated by ASP.NET. Then it looks like.

<script>
   var username = "<%UserName%>";
</script>

This is not safe, because a user can have his/her name to be

</script><script>alert('bug')</script></script>

It is XSS vulnerability.

So, basically, the code should be:

<script>
   var username = "<% JavascriptEncode(UserName)%>";
</script>

What JavascriptEncode does is to add charater "\" before "/" and "'" and """. So, the output html is like. var username = "<\/script>alert(\'bug\')<\/script><\/script>";

Browser will not interpret "<\/script>" as end of script block. So, XSS in avoided.

However, there are still "<" and ">" there. It is suggested to escape these two characters as well. First of all, I don't believe it is a good idea to change "<" to "&lt;" and ">" to "&gt;" here. And, I'm not sure changing "<" to "\<" and ">" to "\>" is recognizable to all browsers. It seems it is not necessary to do further encoding for "<" and ">".

Is there any suggestion on this?

Thanks.

A: 

if I understand the question well, the code is in the server side. so why not use the Server.HtmlEncode()

<script>
   var username = "<%=Server.HtmlEncode(UserName)%>";
</script>
Marwan Aouida
Yes, it is in server side. The situation is that we want some string to have "<" and ">", but not to be displayed. Change ">" to "<" breaks the semantic.
Morgan Cheng
Because encoding needs to be done differently in different contexts, and this is the wrong context for Server.HtmlEncode.
Justice
+5  A: 

The problem has different answers depending on what markup language you are using.

If you are using HTML, then you must not represent them with entities as script elements are marked as containing CDATA.

If you are using XHTML, then you may represent them as CDATA with explicit CDATA markers, or you may represent them with entities.

If you are using XHTML, but serving it as text/html, then you need to write something which conforms to the rules of XHTML but still works with a text/html parser. This generally means using explicit CDATA markers and commenting them out in JavaScript.

<script type="text/javascript">
// <![CDATA[
  …
// ]]>
</script>

A while ago, I wrote a bit about the hows and whys of this.

David Dorward
But still the `>` in `]]>` inside the CDATA block must be repalced by `>`. So `foo[bar[0]]>1234` must be replaced with `foo[bar[0]]<1234` or `foo[bar[0]] > 1234`. Otherwise the CDATA block would be closed prematurely.
Gumbo
David Dorward
Or just add a space: `foo[bar[0]] > 1234` - or if its a part of a string: `'foo[bar[0]]'+'>1234'` - or just contain all your scripts in external .js files.
gnarf
+2  A: 

No, you should not escape < and > using HTML entities inside <script> in HTML.

  • Use JavaScript string escaping rules (replace \ with \\ and " with \")
  • and replace all occurances of </ with <\/, to prevent escaping out of the <script> element.

In XHTML it's more complicated.

  • If you send XHTML as XML (the way that's incompatible with IE) and don't use CDATA block, then you need to escape entities, in addition to JavaScript string escaping.
  • If you send XHTML as XML and use CDATA block, then don't escape entities, but replace ]]> with ]]]]><![CDATA[> to prevent escaping out of it (in addition to JavaScript string escaping).
  • If you send XHTML as text/html (what 99% of people does) then you have to use XML CDATA block, XML CDATA escaping and HTML escaping all at once.
porneL
+2  A: 

The cheap and easy way:

<script type="text/javascript">
    var username = "<%= Encode(UserName) %>";
</script>

where the encoding scheme in Encode is to translate each character of input into the associated \xABCD representation compatible with JavaScript.

Another cheap and easy way:

<script type="text/javascript">
    var username = decodeBase64("<%= EncodeBase64(UserName) %>");
</script>

if you are dealing only with ASCII.

Of course, pst hit the nail on the head with the strict way of doing it.

Justice
+1 Also, this solution makes your output source code look h4x0r!
Jørn Schou-Rode
A: 
<html>
<head>
<title>Example</title>
<script>
var store= new Array(1);
var clcu='0';
var s='0';
var signs="+-*/=";
var strlog="";

function clear1()
{
    //alert("hi");
    document.getElementById('txtdata').value="";
    store[0]=null;
    store[1]=null;
    strlog="";
    document.getElementById('log').innerHTML=strlog;
    //alert("bhj" + obj);

}

function plusmin()
{
    var mch=document.getElementById('txtdata').value.charAt(0);

    if(document.getElementById('txtdata').value.charAt(0)=='-')
    {
        //alert(mch);
        //document.getElementById('txtdata').value.charAt(0)=null;
        var val=document.getElementById('txtdata').value;
        var val1=val.substr(1,val.length);
        document.getElementById('txtdata').value='+'+val1;
    }
    else if(document.getElementById('txtdata').value.charAt(0)=='+')
    {
        //alert(mch);
        var val=document.getElementById('txtdata').value;
        var val1=val.substr(1,val.length);
        document.getElementById('txtdata').value='-'+val1;
    }
    else
    {
        //alert(mch);
        document.getElementById('txtdata').value="-"+document.getElementById('txtdata').value;
    }
}
function calc(sign)
{
    //alert("Hi");
    switch(sign)
    {
        case '+': 
            clcu='+';
            s='+';
            store[0]=parseInt(document.getElementById('txtdata').value);
            //alert(store);
            break;
        case '-': 
            clcu='-';
            s='-';
            store[0]=parseInt(document.getElementById('txtdata').value);
            //alert(store);
            break;
        case '*': 
            clcu='*';
            s='*';
            store[0]=parseInt(document.getElementById('txtdata').value);
            //alert(store);
            break;
        case '/': 
            clcu='/';
            s='/';
            store[0]=parseInt(document.getElementById('txtdata').value);
            //alert(store);
            break;
        case 's':
            clcu='s';
            s='s';
            store[0]=parseInt(document.getElementById('txtdata').value);
            ans=Math.sqrt(store[0]);
            document.getElementById('txtdata').value=ans;
            strlog+=store[0]+"'s sqrt is "+ans+"<br/>";
            document.getElementById('log').innerHTML=strlog;
            //alert(store);
            break;

        case '=': 
            //store.splice(1,0,document.getElementById('txtdata').value);
            //alert(s);
            store[1]=parseInt(document.getElementById('txtdata').value);
            if(s=='+')
            {
                ans=parseInt(store[0])+parseInt(store[1]);
                document.getElementById('txtdata').value=ans;
                strlog+=store[0]+" + "+store[1]+" = "+ans+"<br/>";
                document.getElementById('log').innerHTML=strlog;
                store[1]=null;

                //alert(ans);
            }
            else if(s=='-')
            {
                ans=parseInt(store[0])-parseInt(store[1]);
                document.getElementById('txtdata').value=ans;
                strlog+=store[0]+" - "+store[1]+" = "+ans+"<br/>";
                document.getElementById('log').innerHTML=strlog;


                store[1]=null;
                //alert(ans);
            }
            else if(s=='*')
            {
                ans=parseInt(store[0])*parseInt(store[1]);
                document.getElementById('txtdata').value=ans;
                strlog+=store[0]+" * "+store[1]+" = "+ans+"<br/>";
                document.getElementById('log').innerHTML=strlog;
                store[1]=null;
                //alert(ans);
            }
            else if(s=='/')
            {
                ans=parseInt(store[0])/parseInt(store[1]);
                document.getElementById('txtdata').value=ans;
                strlog+=store[0]+" / "+store[1]+" = "+ans+"<br/>";
                document.getElementById('log').innerHTML=strlog;
                store[1]=null;
                //alert(ans);
            }
            break;


    }


}
function insval(val)
{
    //alert(parseInt(signs.indexOf(clcu)));
    var clcuind=parseInt(signs.indexOf(clcu));
    //alert(clcu);
    //alert(clcuind);
    if(parseInt(signs.indexOf(clcu))>=0)
    {
        //alert("hi");
        document.getElementById('txtdata').value="";
        clcu='0';
        document.getElementById('txtdata').value+=val;
    }
    else
    {
        document.getElementById('txtdata').value+=val;
    //alert(val);
    }


}
var flag=true;
function viewlog()
{
    if(flag)
    {
        document.getElementById('log').style.visibility="hidden";
        flag=false;
    }
    else
    {
        document.getElementById('log').style.visibility="visible";
        flag=true;
        //document.getElementById('log').innerHTML=strlog;
    }
}

</script>
<style>
<!--
.tdcls{
height:20px;
}
-->
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" border="1">
    <tr>
        <td class="tdcls" colspan="5"><input type="textbox" name="txtdata" id="txtdata" readonly></td>
    </tr>
    <tr>
        <td class="tdcls" colspan="5"><input type="button" name="btnclear" id="btnclear" value="clr" onClick="clear1()"></td>
    </tr>
    <tr>
        <td class="tdcls"><input type="button" name="btn1" id="btn1" value="1" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btn2" id="btn2" value="2" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btn3" id="btn3" value="3" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btndiv" id="btn2" value="/" onclick="calc(this.value)"></td>
        <td class="tdcls"><input type="button" name="btnsqrt" id="btnsqrt" value="sqrt" onclick="calc('s')"></td>
    </tr>
    <tr>
        <td class="tdcls"><input type="button" name="btn4" id="btn4" value="4" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btn5" id="btn5" value="5" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btn6" id="btn6" value="6" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btnmin" id="btnmin" value="-"  onclick="calc(this.value)"></td>
        <td class="tdcls">&nbsp;</td>
    </tr>
    <tr>
        <td class="tdcls"><input type="button" name="btn7" id="btn7" value="7" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btn8" id="btn8" value="8" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btn9" id="btn9" value="9" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btnmul" id="btnmul" value="*" onclick="calc(this.value)"></td>
        <td class="tdcls">&nbsp;</td>
    </tr>
    <tr>
        <td class="tdcls"><input type="button" name="btn0" id="btn0" value="0" onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btnplusmin" id="btnplusmin" value="+/-"  onclick="plusmin()"></td>
        <td class="tdcls"><input type="button" name="btndot" id="btndot" value="." onclick="insval(this.value)"></td>
        <td class="tdcls"><input type="button" name="btnplus" id="btnplus" value="+" onclick="calc(this.value)"></td>
        <td class="tdcls"><input type="button" name="btnequ" id="btnequ" value="=" onclick="calc(this.value)"></td>
    </tr>
    <tr>
    <td class="tdcls"><input type="button" name="btnlog" id="btnlog" value="log" onclick="viewlog()"></td>
    </tr>
</table>


<table cellpadding="0" cellspacing="0" border="0">
    <tr>
    <td><td class="tdcls" id="log" colspan="5"></td>
    </tr>
</table>
</body>
</html>
NIRALAGR
I have no idea what this is, but now it's at least readable.
Jørn Schou-Rode
A: 

There is a better way of encoding strings in JavaScript as described in the following post.

http://hemanshubhojak.com/Home/Post?postId=7

Hemanshu Bhojak
This is an approach, but I don't believe we should encourage to do that. Since creating a div then abandon it is not per formant.
Morgan Cheng
Prototype also uses this approach and is effective.
Hemanshu Bhojak
A: 

Prototype js framework provides an escapeHTML function that looks like this:

function escapeHTML() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

pretty simplistic, but this is probably good enough to sanitize input.

BC