Using a JSP, PHP, ASP or later struts and so on friends, do not necessarily know what is a template, but it must be clear that this way of development:
<div class= "M-carousel" > <div class= "m-carousel-wrap" id= "Bannercontainer" > </DIV></DIV&G T;<ul class= "Catelist onepx" onepxset= "" style= "border:0px; position:relative; "id=" navapplication "> <div class=" onepxhelper "id=" onepx1 "></div> <%for (var i=0,len=data.types.length;i<len;i++) {%> <%var _ = data.types[i];%> <%if (_.online) {%> <li data-nav= "<%=_.type%>" > <i data-nav= "<%=_.type%>" class= "ico i-cate <%=_.class%> &L T;%if (_.active) {%>active<%}%> "></i> <span data-nav=" <%=_.type%> "><%=_.name %></span> </li> <%}%> <%}%> </ul>
A variety of <%%> tags, this is the typical template syntax, and this is the HTML templates.
In the HTML5 era, we used static deployment of front-end resources more, and more scenarios needed to populate the page with JSON data returned in the background using the front-end Template library. The front end uses a template library, which is much more elegant than stitching strings manually.
Of course, if the backend uses Nodejs, the front-end Template Library or JS Template Library can be used as compatible.
Here is a very concise template library as an introduction, the author John Resig is the famous jquery founder. The code only chats the number of more than 10 lines:
//Simple JavaScript Templating//John resig-http://ejohn.org/-MIT Licensed//http://ejohn.org/blog/javascript-micro-templating/(function(){ varCache = {}; This. Tmpl =functionTmpl (str, data) {//Figure out if we ' re getting a template, or if we need to //load the Template-and is sure to cache the result. varfn =!/\w/.test (str)?Cache[str]= Cache[str] | |Tmpl (document.getElementById (str). InnerHTML)://Generate A reusable function that would serve as a template //generator (and which'll be cached). NewFunction ("obj", "Var p=[],print=function () {p.push.apply (p,arguments);};" +//introduce the data as local variables using with () {}"With (obj) {P.push ('" +//Convert the template into pure JavaScriptstr. replace (/[\r\t\n]/g, ""). Split ("<%"). Join ("\ T"). Replace (/((^|%>) [^\t]*] '/g, ' $1\r '). Replace (/\t= (. *?) %>/g, "', $, '"). Split ("\ T"). Join ("');"). Split ("%>"). Join ("P.push ('"). Split ("\ r"). Join ("\ \")) + "');} Return P.join (");); //provide some basic currying to the user returnData?fn (data): FN; };}) ();
The key is three parts:
- Use the new function to turn the string into a function;
- Replace stitching with regular expressions, which is the most central and elegant part;
- The data that the user passed in as the scope (using with) is populated into the pits.
First look at a use example, from the use of the example slowly dissect John this artwork.
Console.log (Tmpl ("<span data= ' <% print (1,2,{}); %> ' ><%=name?name:1+1+1%></span> ', {name: ' Kenko '}); // You must add a semicolon after print to separate
The specific syntax is not much explained, and underscore template Library basically consistent, we can refer to: http://underscorejs.org/#template
Chrome runs and will get:
<span data= ' 12[object object] ' >kenko</span>
There are 2 features used here, one is <%=%> Direct output value or calculation results, the second is the use of the built-in print method, can be understood as evaluation, to execute some JS logic.
So, let's take a closer look at the template Tmpl function inside what exactly?
1. See the resulting function
New Function ("obj", "var p=[],print=function () {p.push.apply (p,arguments);};" + "with (obj) {P.push ('" + "<span data=\"); Print (1,2,{}); P.push (' \ ' > ', name?name:1+1+1, ' </span>' + ');} Return P.join (");");
function of the syntax, you can see w3cschool explanation, enough detail: http://www.w3school.com.cn/js/pro_js_functions_function_object.asp
function takes a number of arguments, and the last parameter is the body string, which is the parameter name.
The key is the red part, which is part of the very "art" of regular match substitution, resulting in a string.
2. Take a look at how regular expression substitution works
Console.log ( str.replace (/[\r\t\n]/g, ""). Split ("<%"). Join (' \ t ') . Replace ((^|%>) [^\t]*] '/g, ' $1\r ') . Replace (/\t= (. *?) %>/g, "', $, '") . Split (/\t/). Join ("');" ) . Split ("%>"). Join ("P.push ('") . Split (/\r/). Join ("\ \ ") );
In order to satisfy our prying desire, we put out the source code of the template Library and print it out line by row.
Console.log ( str.replace (/[\r\t\n]/g, "") . Split ("<%"). Join (' \ t ')// . Replace (/((^|%>) [^\t]*] '/g, ' $1\r ') // . Replace (/\t= (. *?) %>/g, "', $, '") // . Split (/\t/). Join ("');") // . Split ("%>"). Join ("P.push ('") // . Split (/\r/). Join ("\ \ ") );
The run will get:
<data= ' print (1,2,{});%>' > =name?name:1+1+1 %></span>
Can find the first half of the <% has become a tab \ t;
Looking at the subsequent output, you can see:
Console.log (Str.replace (/[\r\t\n]/g, ""). SpliT (" /c11> <%"). Join (' \ t ') . Replace ((^| %>)[^\t]*) '/g, ' $1\r ')//key one, in order to be compatible with single quotation marks, replace the single quotation mark with \ r.<spanData= \t\r print (1,2,{});%> \ r>\ t=name?name:1+1+1%></span>. Replace (/\t= (. *?) %>/g, "', $, '")//core, $ $ corresponds to the bracketed content, which is the function of the regular expression. <spanData= \t\r print (1,2,{});%> \ r > ', name?name:1+1+1, '</span>. Split (/\t/). Join ("');") Corresponds to the key above. <spanData= \ r '); print (1,2,{});%> \ r > ', name?name:1+1+1, '</span>. Split ("%>"). Join ("P.push ('")//<spanData= \ r '); print (1,2,{}); P.push (' \ r >', Name?name:1+1+1, '</span>. Split (/\r/). Join ("\ \")//<spanData=\ "); print (1,2,{}); P.push (' \ ')>', Name?name:1+1+1, '</span> );
John cleverly uses \ R and \ t to represent the single quotation mark ('), the left tag (<%), because the two symbols will interfere in subsequent string substitutions, especially single quotes, which is why I deliberately let the data property of span in the example be wrapped in single quotes.
Before and after the two fixed sentence, in fact, the entire template, replaced by a piece of code:
with (obj) {p.push (' <span data=\ ');p rint (, {}); P.push (' \ ' > ', name?name:1+1+1, ' </span> '); }return p.join (");
It might be understood as:
<% ====> ')%> ====> p.push (' = ====> , $ $,
The principle is string splicing, very simple, but the regular expression of this art fan, I can only say imaginative achievement here inexpressible, to John's worship of the feeling arises spontaneously.
================================ meaningless split-line ======================================
Changed a turn, although John this art is absolutely good, but this template library is not absolutely easy to use. In the actual development, we need to keep in mind the XSS prevention, in the traditional jquery modification innerHTML practice, it is easy to XSS.
In the end, the template library needs to be injected into the DOM by innerHTML.
Well, either we do enough XSS checks on the data before passing it to the template Library, especially from the user or a third party, which is vulnerable to XSS attacks without special character escapes.
Generally speaking, we can do simple processing of the data to be filled, the key is & "' characters:
var ESC = function (s) { return s.tostring () . replace (/&# (\d{1,3});/g, function (R, code) {//The purpose here is to prevent repeated ESC execution, causing some characters to escape repeatedly return
String.fromCharCode (code); }). replace (/[& ' "<>\/\\\-\x00-\x09\x0b-\x0c\x1f\x80-\xff]/g,
function
return" + r.charcodeat (0) + ";" /javascript:/g, "
Then, if the template library is unified to do XSS escaping, things will surely become simpler.
So, we're trying to add the ESC function to the template library.
The template Library has two places where user data is injected into the DOM:
- Print function
- . replace (/\t= (. *?) %>/g, "', $, '"), a place like <%=name%>.
Because the new function turns the functional body string into an actual function, it is not possible to access the current context (closure) in the function as usual, and access only the parameters or global variables/methods specified at the function build.
So, we can pass ESC as an argument to function, and the template Library eventually changes to:
varfn =!/\w/.test (str)?Cache[str]= (Cache[str] | |Tmpl (document.getElementById (str). InnerHTML)): NewFunction ("obj","ESC","Var p=[],print=function () {for (Var i=0;i<arguments.length;i++) {P.push (ESC (Arguments[i]));}};"+" with (obj) {P.push (' "+ str.replace (/[\r\t\n]/g," ""). Split ("<%"). Join (' \ t '). Replace (/((^|%>) [^\t]*] '/g, ' $1\r '). Replace (/\t= (. *?) %>/g, "',ESC ($),‘")//ESC cannot be an external local variable and cannot form a closure. So it's either defined within the function, or it's a global function, or as a parameter. Split (/\t/). Join ("');"). Split ("%>"). Join ("P.push ('"). Split (/\r/). Join ("\ \" ") + "');} Return P.join (");); //provide some basic currying to the user returnData? FN (data, ESC) :function (param) {return fn (param, ESC)};//Curry approach. First, a compiled render function is returned, and the user can delay rendering
Take an example of an attack to see the effect:
var name = ' <script>alert (1) </script> oh hehe '; var age = ' \ ' onclick= ' alert (1) ' document.write (Template (' <span data= ' <%=age%> ' > <%=name%></span> ', {name:name, age:age});
Suppose we get the URL parameter name and age, and then fill it directly into the page. If we use the original template library, we can see ... Alert ... Of course, hackers can be replaced with meaningful code, such as getting your password, sending a tweet, sending a space, and even transferring your virtual gold coins.
Look carefully, Dom is full of attack code
Not only the page just opened the script tag attack, as well as the span node onclick attack, when clicking on the span, will execute a section of JS ...
Next, we witness the magical moment!!! Replace the template Library with the automatic escape of XSS.
Both attacks were filtered, leaving only the clever plain text. Hey
Finally, to say something about underscore, the underscore template Library principle is similar to John's Lite version, and also regular + string substitution.
However, the difference is that underscore is more sophisticated, providing two ways to inject data:
- <%=name%> This, like John's, did not do any filtering;
- <%-name%> This has the escape of doing a few key characters, including & "'
Of course, we can also make the first pattern automatically escaped, as I do now the project needs to do ... That's about 1239 lines of code, and the following red part is what I changed.
if(Escape) {Source+ = "' +\n ((__t= (" + Escape + ")) ==null": _.escape (__t)) +\n ' "; } if(interpolate) {source+ = "' +\n ((__t= (" + interpolate + ")) ==null? ':_.escape (__t)) +\n ' "; } if(Evaluate) {source+ = "'; \ n" + Evaluate + "\n__p+="; } Index= offset +match.length; returnmatch; }); SOURCE+ = "'; \ n"; //If A variable is isn't specified, place data values in local scope. if(!settings.variable) Source = ' With (obj| | {}) {\ n ' + source + '}\n '; SOURCE= "var __t,__p=", "+"print=function () {for (Var i=0;i<arguments.length;i++) {__p + = _.escape (Arguments[i]);}};\ N" +Source+ "return __p;\n";
Brief analysis of the principle of "ultra-thin JS Template Library/front-end formwork library" and Prevention of XSS