How do I prevent html element from escaping parent? (security) - javascript

I tried to Google this, but everything is related to css, not security.
I have this as a comment form:
<pre name="comment">
<comment-content>
This is a sample comment by a user
</comment-content>
</pre>
I allowed some controlled html tags that include [pre][/pre] and this is where the problem starts.
if I do something like this:
<pre name="comment">
<comment-content>
This is a sample comment by a user
[/pre]
This text will be outside the comment container
</comment-content>
</pre>
The comment escapes the pre tag, and ignores that its inside the <comment-content></comment-content> tag. I added this tag as an attempt to block escaping, but it doesn't work. I also notice my controlled html tags will run outside the container. I have a second container that is not escaped, but this issue with escaping the first container means if I put a <pre> tag outside that container, it could be escaped. I also tried doubling up the container, but that did not work either.
Here is an image of the [/pre] tag escaping the container
here is a quick sample of what javascript is doing in the background:
//I added .cleanHTML() as a similar function to php htmlentities() and .clean() is similar to php strip_tags()
let content = $(this).html().cleanHTML().clean();
commentHtml += '<pre name="comment" type="text/plain"><comment-content>'+setUserCommentHtml(content.clean())+'</comment-content></pre>';
$(this).html(commentHtml);
Note: I am aware that most security should be done server side, but would also like to keep client side secure as well.
I basically need a way to force html to require the first closing tag before the second parents closing tag will work.

Posting solutions (with help from comments) as an answer to mark as solved.
Jared Farrish answered question in comments.
changing my javascript to something like this fixes the issue:
//I added .cleanHTML() as a similar function to php htmlentities() and .clean() is similar to php strip_tags()
let content = $(this).html().cleanHTML().clean();
let setContentId = Math.floor(Math.random()*10000);
commentHtml += '<pre name="comment" type="text/plain"><comment-content set-content="'+setContentId+'"></comment-content></pre>';
$(this).html(commentHtml);
$('comment-content[set-content="'+setContentId+'"]').html(setUserCommentHtml(content.clean()));
I also added this method Inside the setUserCommentHtml() function.
let htmlOpenTags = [];
//in a loop
if(tagType === 'close' && htmlOpenTags.includes(commentTag)){
htmlOpenTags.splice(htmlOpenTags.lastIndexOf(commentTag));
//close tag here
...
}else if(tagType === 'open'){
htmlOpenTags.push(commentTag);
//open tag here
...
}
If I push to an array, every time the user opens a tag, Then I can verify the opened tag exists in that array before closing it and remove that tag from the list.
edit: stack overflow says I must wait 2 days before marking as answer

Related

need to add contentEditable=false to p tag inside CKEditor

i need inside my CKEditor some boilerplate verbiage that is not editable, then the rest of the my string information. I concatenate the boilerplate verbiage [which is in a p tag], to a string variable that my CKEditor displays inside a certain div. By the time the verbiage, here:
<p id='abc' contentEditable='false'>verbiage</p>
... and the string information is displayed on the page, they are deep inside a number of nested tags - within a body with multiple classes. So both the verbiage, which is now in only a p tag with no attributes[they got stripped out], is nested way inside the original body tag [the first body tag, way up in the page] with lots and lots of divs, then finally comes an iframe, then ... the verbiage and string are like this:
<body contenteditable="true" class="cke_editable cke_editable_themed cke_contents_ltr cke_show_borders" spellcheck="false">
<p>boilerplate verbiage</p>
...then the rest of the information is displayed in the editor, inside various spans, etc. i need to make the boilerplate verbiage readonly, contentEditable='false'. Yet everything I try both from the console in Chrome, and in code.... nothing changes that boilerplate verbiage tag. i have tried various things, including these - perhaps you can see where I need to tweak something; and i hope this will show you things i have tried and that i am run out of options so far:
jQuery("body.cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders").first().contentEditable='false';
jQuery("body.cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders").attr("readonly", "1");
jQuery("body.cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders p:first-child").contentEditable='false';
jQuery("body.cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders").find( "p" ).contentEditable='false';
jQuery("iframe", ".cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders").contents().find("p").contentEditable='false';
jQuery("iframe", "body .cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders").contents().find("p").contentEditable='false';
var editor= jQuery("body", ".cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders");
editor.val(editor.val().replace(/<p>/gi, "<p class='tiny_p'>"))
var editor= jQuery("body.cke_editable.cke_editable_themed.cke_contents_ltr.cke_show_borders");
editor.val(editor.val().replace(/<p>/gi, "<p class='tiny_p'>"))
yet if i hard code in the Chrome browser, contenteditable="false",
it works perfectly. So, how can i access that p tag and assign it this attribute?
It really depends on moment and how you want to access, one option to access directly from separate script.
CKEDITOR.instances[YOUR_INSTANCE].window.$.document.getElementById("your_p_tag")
Note, that it should be done after CKEDITOR initilized
UPDATE:
CKEDITOR.instances[YOUR_INSTANCE].window.$.document.body.firstChild

Automatically end self closing tag in Jquery

I get the below response from my service . I need to automatically add a self closing tag to it to structure my DOM.
How can I achieve this in Jquery or Angular JS.
Input :
<link><br><br><b>Hello .This is my input
Output :
<link><br><br><b>Hello .This is my input</b></link>
Start input tags can be any, therefore I cannot add explicit logic for link and bold tags.
Your inputs are appreciated.
try using "angular.element". This will take care of closing tag automatically.
Example:
angular.element("<b>").text("Hello .This is my input")
This can be done using DomParser. The exact levels of closing tags can be achieved using xml type.
var dom = new DOMParser().parseFromString(i, "text/xml");
var removeParserErrorElem = dom.childNodes[0].getElementsByTagName("parsererror")[0];
dom.childNodes[0].removeChild(removeParserErrorElem);
The html will be in: dom.childNodes[0];
but it will also make br tags as opening and closing, you will have to handle that in some logic.
Give this one a try Jquery Clean
EDIT: If you get the OuterHTML, you will get the html. but for <br /> tags for example, it returns <br> opening tag and </br> closing tag.
var target = dom.childNodes[0].outerHTML; //this returns the fixed html with impreper BR tags.
target.split("</br>").join("");
target.split("<br>").join("<br />"); // target now has the fixed HTML.

jQuery empty textarea that contains data

Curious problem. I need to empty a <textarea> then replace it with other content. The tests in the JSFiddle will work if nothing is manually typed, but as soon as anything is entered in the textarea by hand, the methods will cease to work.
http://jsfiddle.net/ecFjH/
I understand that I can simply just .val('New stuff here'), however I need HTML entities such as > and < to appear as < and >, which .val() will not accomplish.
It sounds like your real problem is that you want to decode HTML entities to render them in a text area. You could use the following to do this:
var content = 'text > HTML';
$('#myText').val($('<div/>').html(content).text());
However, you should only do this with trusted content. If the content for the textarea is not created by you, it could contain malicious HTML, which you would unsafely be creating on the page.
For a more thorough example, see this answer to essentially the same question; note that the accepted answer repeats the above, but the linked answer is safer.
Your text area has no html. use just $('#myText').val('Button 2 was pressed'); that will remove the previous content and put the text "Button 2 was pressed".
Check here (updated with < and >)

Expansion of Struts 2 Tags Messes Up Rendering Of Page

Often times, when I use struts 2 tags, the loading of a page will be incomplete apparently because of single quote or double quote characters from the struts 2 tag interfering with such characters from javascript.
One example I am very eager to get working is as follows:
var me = '<s:a href=\'http://www.google.com\'>Google Link</s:a>';
$('#appnSelect').html(me);
So what I am concerned about is when single and double quotes are inside that me string on the right side of line 1. Ultimately, I need to get <s:select> to work, but this problem seems to creep in with a number of tags like the above example. Replace the <s:a> tag with an <a> tag, and voila, it works. However, when the <s:a> tag gets expanded, the page will incompletely load.
Is there an easy solution somewhere I am missing? One thing I did try was with the theme attribute setting theme="simple" because sometimes that helps me when the output gets rendered incorrectly. That did not work in this case.
Generating HTML from tags like that in the middle of a JavaScript string constant is always going to be an ugly business. In addition to quote characters, you're also likely to get newlines. Strictly speaking you don't know what you're going to get, and you can't control it.
One thing that comes to mind is that you could drop the tags into dummy <script> blocks marked as a non-JavaScript type:
<script id='anAnchor' type='text/html'>
<s:a href='http://www.google.com'>Google Link</s:a>
</script>
The browser won't try to execute that. You can then do this in your JavaScript code:
$('#appnSelect').html($('#anAnchor').html());
What should work with very little thinking:
<s:a id="google" style="display: none;" href="www.google.com">Google Link</s:a>
Now just grab the the element using the id in your script. Might be better if you set up a class. There are id, style and class attributes for all struts2 tags.
I believe the issue is with your escaping of the single quotes inside the <s:a> tag. In my experience with using <s:url>, I've done the following:
var url = "<s:url value='/someAction.action' />"
I believe the same syntax should hold true for <s:a>.
Additionally, look in your JSP container's error log, and see if you can find an error relating to that <s:a> tag. That may provide some additional insight to the problem.
This is my answer, which will not be the best answer because Pointy's response pointed me in the correct direction. However, up votes still appreciated :)
First, you need the script blocks which are not rendered. I have 2 because a checkbox will toggle between which one is displayed:
<script type="myType" id="abc">
<s:select name="selectName" list="#list1" listValue="%{prefix + '-' + name}" theme="simple"/>
</script>
<script type="myType" id="abc2">
<s:select name="selectName" list="#list2" listValue="%{prefix + '-' + name}" theme="simple"/>
</script>
Next, I create a region which is blank in the html code
<div id="innerRegion">
</div>
Then, I need to put something on the screen when the page first comes up, so go with this:
<script type="text/javascript">
$(document).ready(function(){
$('#innerRegion').html( $('#abc').html() )
});
I needed to put this at the end of my document because onLoad was already being used by a parent page. So I am saying abc is the correct default.
Then I need logic to handle what happens when the checkbox is pushed:
var buttonPressed = false;
$(window).load(
function()
{
LocalInit();
});
function LocalInit() {
$('#myForm input[name=buttonValue]').change(
function()
{
buttonPressed = !buttonPressed;
if (buttonPressed == true)
{
$('#innerRegion').html( $('#abc2').html() )
} else
{
$('#innerRegion').html( $('#abc').html() )
}
$('#dataId').href = document.location.href;
}
);
}
I think what was tripping me up ultimately was that I was trying to force the s:select tag through jQuery functions when as you see above it did not turn out to be necessary. I could just write the s:select as normal.

HTML within Javascript Function Not Working Properly

I am using the following JavaScript function:
function Projects()
{
var PrjTb1 = "<input type=text id=PrjNme size=100/>"
var PrjTb2 = "<textarea rows=5 col=200 wrap=hard></textarea>"
var Info = "1. Project or activity name:<br>" + PrjTb1 + "<br><br>2. Project or activity description:<br>" + PrjTb2
if (document.getElementById('PrjNo').value == 1)
{
document.getElementById('AllPrj').innerHTML = "<b>Project or activity 1.</b><br><br>" + Info
}
}
This function executes well, after an onclick event; however, certain portions of the HTML within the declared variables are not working. For example, within the variable PrjTb2, my textarea's rows and columns do not change. Also, I cannot add the HTML tags <dd> and </dd> anywhere within the variables to create an indentation. What is interesting is that both the textarea properties and the HTML tags, <dd> and </dd>, work within the body of my form, just not in my JS function. Would anyone know what I am doing wrong.
Not sure if its the problem, but I'd enclose all your parameters in quotes.
<input type=text id=PrjNme size=100/>
should really be:
<input type='text' id='PrjNme' size='100' />
additionally, depending on your Doctype, you may want to change
<br>
to
<br />
Things that are allowed in direct HTML are not necessarily allowed using innerHTML. For example, in Firefox, try embedding a form within a form in JS vs html, or in IE, try putting a block element inside an inline element. They both work fine, if you have it in HTML, but if you try it with innerHTML, both browsers will complain.
It could be that your browser is caching your Javascript. Try clearing your cache.
I don't know if your syntax error are due to copying you code here, but here is a couple of things I noticed in your code.
Are you omitting semi-columns at the end of you lines on purpose?
HTML proprieties should be surrounded by quotation marks. (Although not necessary)
Also regarding the <dd></dd>, did you put those inside a definition list (dl)?
Because they shouldn't be used as standalone tags.

Categories