Dynamic evaluation of functions in JS (is this safe?) - javascript

I have a website in which all the pages are processed through an index.php that includes different PHP files depending on the requested URL (this is done through mod_rewrite).
I'm using the following method to execute specific functions at page load:
index.php
<script type="text/javascript">
readyFns = Array();
</script>
<?php
// Do some stuff here, and pull the name of the PHP page to include from the DB
include $pageToInclude
?>
<script type="text/javascript">
commonFunctionToApplyToAllThePages();
otherCommonFunction();
// page-specific functions
for (i=0; i<readyFns.length; i++)
{
if (typeof(window[readyFns[i]]) == "function")
window[readyFns[i]]();
}
</script>
includedPage.php
<?php
// Generate page
?>
<script type="text/javascript">
readyFns.push("someFunction");
readyFns.push("someOtherFunction");
</script>
I quite like this approach because I just have to set readyFns at the end of this page and everything else will be nicely controlled by index.php.
My questions is: is this safe? Could it be sensitive to someone generating a link that arbitrarily sets readyFns to point to some malicious code and then links to my site?
How would I prevent that?
thanks
nico

This is interesting. In principle, it's probably ok, but you're right to be a little concerned. This is just compiling a list of keys to lookup as functions on an object, and execute, so it's not really a security problem in that respect. But, you are essentially providing access to all globals like that. You'd probably be better off making a global object besides window to store your functions on, like so:
var funcs = {};
funcs.someFunction = function() {/*blah*/};
funcs.someOther = function() {/*blah*/};
and then your readyFuncs thing would loop over funcs instead of window. I don't think there'd be anything to worry about past that.
Of course, there are other things with your approach that could be improved, but I think it's ok as-is if it works for you.

Related

What could be causing: "Uncaught TypeError: this.captcha_ip.form.submit is not a function" in this (downloaded) javascript?

I'm a total noob to javascript and also this is my first time doing anything but reading this website so maybe I have gone about this all wrong. I've been using PHP+HTML as a hobby for almost 20 years for basic, static websites, but for an M.Arch university project I decided to build a website for a zine, which includes a contact form where I'd like people to be able to submit articles and attachments.
I downloaded an example form and reskinned it to fit the site, but for some reason, the javascript - which I haven't altered in any way - doesn't seem to work. The source website ( https://html.form.guide/contact-form/contact-form-attachment/ ) doesn't seem to have a contact form for me to ask them what's what, and a bit of googling and looking through other stack overflow questions isn't helping, possibly because I don't know enough about javascript to even have the right keywords.
When I inspect the form in my browser, clicking the submit button brings up this error:
Uncaught TypeError: this.captcha_ip.form.submit is not a function
at FG_CaptchaValidator.OnSuccess (fg_captcha_validator.js:42)
at _OnSuccess (fg_captcha_validator.js:120)
at XMLHttpRequest._StateHandler (fg_captcha_validator.js:143)
Here's the function in the downloaded javascript (I really have absolutely no clue where to even begin to bugtest something like this) that the line is part of:
function FG_CaptchaValidator(captcha_ip,captcha_img)
{
this.captcha_ip = captcha_ip;
this.captcha_img = captcha_img;
this.validatedCode=''
this.validate = function()
{
if(this.validatedCode.length==0 ||
this.validatedCode != this.captcha_ip.value)
{
this.ValidateOnline();
return false;
}
else
{
return true;
}
}
this.OnSuccess = function()
{
var msg = this.GetResponseText();
if(msg == 'success')
{
this.validatedCode = this.captcha_ip.value;
if(this.captcha_ip.form.onsubmit())
{
this.captcha_ip.form.submit();
}
}
else
{
sfm_show_error_msg(msg,this.captcha_ip);
document.error_disp_handler.FinalShowMsg();
}
}
this.ValidateOnline = function()
{
var url = captcha_img.src;
var postStr = this.captcha_ip.name + "=" +
encodeURIComponent( this.captcha_ip.value )+'&fg_validate_captcha=y';
this.Init('POST', url);
this.Send(postStr);
}
}
I hope there's something obvious that's just slightly off in this code, because I really don't know where to start with javascript. I know it's a bit like PHP, lots of similar functionality, just at different ends... but the actual syntax..?
If it's not this code, then perhaps I've messed something up in my reskin of the contact form itself, or the way the scripts are included, or, I don't know.. Any guidance would be appreciated!
EDIT TO BRING STUFF IN FROM COMMENTS/ELABORATE: Within my <head> section for every page I bring in metajava.php: <?php require("metajava.php"); ?> within that file I have the scripts included (amongst others): <script type="text/javascript" src="scripts/gen_validatorv31.js"></script> <script type="text/javascript" src="scripts/fg_captcha_validator.js"></script>
I think these two scripts must be getting included correctly, or the browser's inspection console (I use Brave) wouldn't be pointing me to the proper line of the script in the error, and the scripts wouldn't show up in the sources tab(?)
I don't get any 404 errors; the form simply does not submit or appear to do anything unless I'm inspecting the page and see the console error. If I click submit once (with the inspect console open) I get the error I quoted at the beginning, and if I slam it repeatedly like the migrainous bean I am lately, I get a 500 error.
I've also done a little test of the PHP includes by way of adding
echo "filename-for-each-required-include.php included"; to each php include with the title of the file, and they all come in at the top correctly, though it breaks the captcha so I've removed it again now that I know they're working.
I still wonder if it's a javascript syntax thing that I'm not picking up bc I don't know anything really about javascript. I have modified a few simple scripts before but it was VERY trial and error and this is such a complicated looking expression I don't know where to start - is it even meant to be a function?
PS: Thanks for literally YEARS of solving my problems without my even needing to sign up and ask <3

javascript , HTML, difference between writing javascript in head and body

I am learning javascript and to tell the truth, some parts don't make sense to me. like this one. I wrote this block of code first :
<body>
<script type="text/javascript">
function people(name, age){
this.name = name;
this.age = age;
this.ret = yearsLeft;
}
function yearsLeft(){
var numYears = 65 - this.age;
return numYears;
}
var sam = new people("sam forest", 39);
var billy = new people("billy wood", 45);
document.write(billy.ret());
</script>
</body>
and I got the result. However I wrote this one after the first one and I got the same result:
<head>
<title>Javascript</title>
<script type="text/javascript">
function people(name, age){
this.name = name;
this.age = age;
this.ret = yearsLeft;
}
function yearsLeft(){
var numYears = 65 - this.age;
return numYears;
}
var sam = new people("sam forest", 39);
var billy = new people("billy wood", 45);
</script>
</head>
<body>
<script type="text/javascript">
document.write(billy.ret());
</script>
</body>
Here is my question, what is the difference , when I get the same result in both ways?
From Yahoo's Best Practices for Speeding Up Your Web Site:
The problem caused by scripts is that they block parallel downloads.
The HTTP/1.1 specification suggests that browsers download no more
than two components in parallel per hostname. If you serve your images
from multiple hostnames, you can get more than two downloads to occur
in parallel. While a script is downloading, however, the browser won't
start any other downloads, even on different hostnames.
In some situations it's not easy to move scripts to the bottom. If,
for example, the script uses document.write to insert part of the
page's content, it can't be moved lower in the page. There might also
be scoping issues. In many cases, there are ways to workaround these
situations.
An alternative suggestion that often comes up is to use deferred
scripts. The DEFER attribute indicates that the script does not
contain document.write, and is a clue to browsers that they can
continue rendering. Unfortunately, Firefox doesn't support the DEFER
attribute. In Internet Explorer, the script may be deferred, but not
as much as desired. If a script can be deferred, it can also be moved
to the bottom of the page. That will make your web pages load faster.
Therefore, in general, it is preferrable to put them at the bottom. However, it isn't always possible, and it often doesn't make that much of a difference anyway.
In many cases the result is the same, but there's a relevant difference due to the way web browser render html pages.
Since a browser reads the page content top-to-bottom, placing the javascript code within the <head> tag will cause the actual page content to be displayed after the browser has finished parsing the script. Placing it just before the </body> tag instead will let the browser display the content faster, which is usually desirable.
Another implication of the top-to-bottom rendering is related to SEO optimization: since most crawlers will inspect a fixed number of bytes at the top of a page, having those first bytes filled with javascript code will prevent the crawler from accessing the actual page content, therefore reducing the benefits of whatever you've SEO-wise.
Because you're doing pretty much the same thing. The browser is going to evaluate your javascript code sequentially, and, if it's just statements, as you putted, they're going to be executed.
So, one thing you need to pay attention is that the browser is going to evaluate your hole document (html, css, javascript), and the javascript statements that are not function definitions are going to be executed right away.

Updating content in a Google Apps Script sidebar without reloading the sidebar

I am using the following Google Apps Script code to display content in a custom sidebar of my spreadsheet while the script runs:
function test() {
var sidebarContent = '1<br>';
updateSidebar(sidebarContent);
sidebarContent += '2<br>';
updateSidebar(sidebarContent);
sidebarContent += '3';
updateSidebar(sidebarContent);
}
function updateSidebar(content) {
var html = HtmlService.createHtmlOutput(content)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('Sidebar')
.setWidth(250);
SpreadsheetApp.getUi().showSidebar(html);
}
It works, but each time the updateSidebar() function runs, the sidebar blinks when loading in the new content.
How can I program this to update the content of the sidebar more efficiently, thus removing the blink?
I'm assuming that SpreadsheetApp.getUi().showSidebar(html); should really only be run once, at the beginning, and the subsequent updates to the content should be handled by Javascript in a .js file.
But I don't know how to get the sidebarContent variable from Javascript code running client-side in the user's browser.
Also, I know this must be possible, because I just saw this post on the Google Apps Developer Blog today about an app that uses a custom sidebar, and the .gif towards the end of the article shows a nicely-animated sidebar that's being updated in real-time.
I believe the solution for this situation is to actually handle the flow of the server-side script from the client-side. That is the only way I can think of right now to pass data to the client side from the server without re-generating the HTML.
What I mean by this is that you would want to make the calls to the server-side functions from the client, and have them return a response as a success handler to the client. This means that each action that needs to be logged will need to be made into its own function.
Ill show you a quick example of what I mean.
Lets say your server-side GAS code looked like this:
function actionOne(){
...insert code here...
return true;
}
function actionTwo(){
...insert code here...
return true;
}
And so on for as many actions need to be executed.
Now, for your .html file, at the bottom you would have javascript looking something like this:
<script>
callActionOne();
function callActionOne(){
google.script.run.withSuccessHandler(callActionTwo).actionOne();
}
function callActionTwo(){
...update html as necessary to indicate that the first action has completed...
google.script.run.withSuccessHandler(actionsComplete).actionTwo();
}
function actionsComplete(){
..update html to indicate script is complete...
}
</script>
It is a bit more complex than is ideal, and you might need to use the CacheService to store some data in between actions, but it should help you with your problem.
Let me know if you have any questions or if this doesn't fit your needs.

Accessing array in another JS file - Chrome Extension

Hi I am making a chrome extension for some practice that is a simple website blocker. I have two different JS files that are needing to share the same array that contains URLs to be blocked.
background.js handles the webRequests and blocking websites
options.html is the options page where users can edit URLs to be blocked, it calls storeURL.js so that it can store all the elements in the list on the html page into a js array. No problem so far.
However I cannot access the array inside of storeURL.js from background.js. It seems as if they are being called in two separate instances. If I try to include both storeURL.js and background.js inside of my background.html, that results in two totally separate storeURL.js scripts running.
How should I go about doing this? Should I store the array contents from storeURL.js into a file?
Some examples:
background.js
chrome.webRequest.onBeforeRequest.addListener(
blocking,["blocking"]);
{ urls: blockedURLS, types: [] }, ["blocking"]);
storeURL.js populates the array based on the list in options.html
var blockedURLS = [];
$('li').each(function(i, elem) {
blockedURLS.push($(elem).text());
});
blockedURLS in my background.js appears as undefined. I have also tried to point my options.html file to background.js and just include all of the js in one file with the following:
<script type="text/javascript" src="background.js"></script>
However when I do this it seems that a second background.js is called rather than just pointing to the one already running.
Feels like I've reached a dead end with possibly a simple solution that is available to fix my problem. I'm fairly new to JS/chrome extensions as well.
Thanks for taking the time to read this!
EDIT:
After some more fiddling I am able to access my blockedURL array in my background.js. However it is never updated.
var blockedURLS = ["hi"] ;
var list = document.getElementById('list');
$("#saveList").click(function(e) {
e.preventDefault();
localStorage.setItem('todoList', list.innerHTML);
alertify.success("You have saved your list.");
//Pushes each element in the list from options.html into the urls array
blockedURLS = [];
$('li').each(function(i, elem) {
blockedURLS.push($(elem).text());
});
alert("Currently blocked:\n" + blockedURLS);
});
$("#reset").click(function(e) {
e.preventDefault();
localStorage.clear();
location.reload();
});
loadToDo();
function loadToDo() {
if (localStorage.getItem('todoList')){
list.innerHTML = localStorage.getItem('todoList');
}
}
What should be happening is that after I go into my options.html and save the list, "hi" should be replaced with all the different URLs I have in my list. However it is not. The blockedURL array is printed correctly in that alert though.
I haved to work with that kind of thing recently. I have never find a really good way to do... So I have used the Storage api of Chrome Extension API. But it's not really funny to use because all methods are asynchronus so you can't simply do
myValue = chrome.storage.local.get("MyValue")
If you want I have made an object that store data automatically in the chrome storage but allows simple and synchronus calls like myValue = storage.myValue or storage.myValue = "something"
Here the github link
It was written in CoffeeScript so you can find javascript file in bin folder. The generated javascript is not very easy to read/modified but you can understand the idea simply by reading the CoffeeScript code I guess.
I can explain more how it works if you want. Tell me in comment and I will update my response.
And pay attention that it's a code I have written for my use so it's not the cleaner and bugless code that I have ever made :-) but it works fine.
EDIT : I have forget to says that you need to include this tow files in all pages / Content Script where you need to use it, of course.
Ho and sorry for my poor english... it's not actually my principal language ;-)
I had to use the following command:
var bg = chrome.extension.getBackgroundPage();
then I could access the blockedURLS array by:
alert(bg.blockedURLS);
and also edit the array by
chrome.extension.getBackgroundPage().blockedURLS = [];
which would set it to an empty array.
Thanks guys for the help, it helped me in thinking of different possibilities on approaching this problem.

Disable javascript entry into form

I'm creating a "HTML editor" for a webpage of mine. At the moment, I only want the editor to allow entry of HTML and CSS elements and not Javascript (or Jquery for that matter).
I'm trying to find a way that disables the use of <script> or <script type="text/javascript"> </script> using PHP. However the current way outputs a messy result!
$content_in_before = str_replace('<script','',$content_in_before);
$content_in_before = str_replace('script>','',$content_in_before);
It's also not very well coded!
Is there a more bulletproof way of coding this, stopping all type of Javascript from being entered into this form? (While still allowing CSS and HTML)?
Thanks in advance!
I'd recommend using a sanitization library, like HTML Purifier, since just stripping <script> tags isn't enough to prevent XSS attacks, since JS can be automatically executed using attributes like onLoad, onMouseOver, onUnload, etc.
To remove tags, and allow some, you can use PHP's strip_tags() function, but it doesn't strip the attributes, hence my recommendation for a HTML sanitization library. If you're able to run it, perhaps one of the best choices is Google's Caja library, albeit it doesn't work in shared hosting environments since it's written in Java, but it can be hosted on Google's AppEngine.
Also, simple regex solutions aren't always reliable, since even malformed tags can still be parsed. For example, <script > wouldn't be caught by simple regex detection of normal script tags unless it's looking for spaces after the tag name. It's possible to check for this, but using an established library would save you time, and would give you the added bonus of a battle-tested library.
Example:
Script Tags with Spaces producing an alert
You could you a regexplike this
echo preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', "", $var);
source: https://stackoverflow.com/a/1886842/2046700
or as stated us a libary to do this for you such as:
http://htmlpurifier.org/
another possible example:
<?php
$javascript = '/<script[^>]*?javascript{1}[^>]*?>.*?<\/script>/si';
$noscript = '';
$document = file_get_contents('test.html');
echo preg_replace($javascript, $noscript, $document);
?>
Whitelist tags you permit, and attributes you permit, then remove everything else. You can use DOMDocument for this.
I wrote this piece of code once but never had anyone else review it
function legal_html($str, $tags='<a><b><br><i><span><table><tbody><tr><td><thead><th><img>', $attribArray=false) {
if ($attribArray===false) {
$attribs = array('id','class','src','href','alt');
} else {
$attribs = $attribArray;
}
$stripped = strip_tags($str,$tags);
$dom = new DOMDocument();
#$dom->loadHTML('<div>'.$stripped.'</div>');
foreach ($dom->getElementsByTagName('*') as $node) {
for ($i = $node->attributes->length -1; $i >= 0; $i--) {
$attrib = $node->attributes->item($i);
if (!in_array($attrib->name,$attribs)) $node->removeAttributeNode($attrib);
}
}
$stripped = $dom->saveHTML();
$start = strpos($stripped,'<div>')+5;
$end = strrpos($stripped,'</div>');
$stripped = trim(substr($stripped,$start,$end-$start));
return $stripped;
}
You can use something likes this-
$content=$_POST['textbox'];
if(strpos($content,'<script>')!==false){
//show error;
}
else{
//proceed with work;
}

Categories

Resources