Yeah, avoid HTML string-slinging. You're giving yourself bugs and potentially cross-site scripting security holes. For example:
'<a href="'+img.parent().attr('href')+'">'
what if the URL in the parent's href
contains characters that are special in this HTML context, like <
, "
or &
? At best you'll get invalid markup that might trip the browser up; at worst, if the URL comes from user submission, a security problem.
(OK, <
and "
are unlikely to appear in a URL, but &
is very likely indeed. The title
you're putting in the text content may be more vulnerable.)
This is a large and increasing problem. Just as we're starting to get a handle on fixing the HTML-injection bugs coming from templating on the server-side (eg. PHP users forgetting to htmlspecialchars()
), we're now introducing loads of new client-side XSS from naïve HTML-hacking with innerHTML
and jQuery's html()
. Avoid.
You can escape text you're inserting into HTML manually:
function encodeHTML(s) {
return s.replace(/&/g, '&').replace(/</g, '<').replace(/"/g, '"');
}
'<a href="'+encodeHTML(img.parent().attr('href'))+'">'
but really, you're better off using the direct DOM-style properties and methods, which, since they involve no HTML parsing, don't require any escaping. They're called DOM-style because that's the way the original DOM Level 1 HTML features work (which existed back before innerHTML
reared its ugly head):
var a= document.createElement('a');
a.href= this.parentNode.href;
a.appendChild(document.createTextNode(this.title));
In jQuery you use attr()
and text()
to do the same:
var a= $('<a></a>');
a.attr('href', $(this).parent().attr('href');
a.text($(this).attr('title'));
And in jQuery 1.4, you can do it most conveniently using an element creation shortcut:
$(this).append(
$('<p class="cap"></p>').append(
$('<a></a>', {
href: $(this).parent().attr('href'),
text: $(this).attr('title')
})
)
);
This still looks a bit questionable though, what's the parent that you're getting the href
from? It's invalid to put a <p>
, or another link, inside a link.