Intro
This topic has been the bane of many questions and answers on StackOverflow -and in many other tech-forums; however, most of them are specific to exact conditions and even worse: "over-all" security in script-injection prevention via dev-tools-console, or dev-tools-elements or even address-bar is said to be "impossible" to protect. This question is to address these issues and serve as current and historical reference as technology improves -or new/better methods are discovered to address browser security issues -specifically related to script-injection attacks.
Concerns
There are many ways to either extract -or manipulate information "on the fly"; specifically, it's very easy to intercept information gathered from input -to be transmitted to the server - regardless of SSL/TLS.
intercept example
Have a look here
Regardless of how "crude" it is, one can easily use the principle to fabricate a template to just copy+paste into an eval() in the browser console to do all kinds of nasty things such as:
console.log() intercepted information in transit via XHR
manipulate POST-data, changing user-references such as UUIDs
feed the target-server alternative GET (& post) request information to either relay (or gain) info by inspecting the JS-code, cookies and headers
This kind of attack "seems" trivial to the untrained eye, but when highly dynamic interfaces are in concern, then this quickly becomes a nightmare -waiting to be exploited.
We all know "you can't trust the front-end" and the server should be responsible for security; however - what about the privacy/security of our beloved visitors? Many people create "some quick app" in JavaScript and either do not know (or care) about the back-end security.
Securing the front-end as well as the back-end would prove formidable against an average attacker, and also lighten the server-load (in many cases).
Efforts
Both Google and Facebook have implemented some ways of mitigating these issues, and they work; so it is NOT "impossible", however, they are very specific to their respective platforms and to implement requires the use of entire frameworks plus a lot of work -only to cover the basics.
Regardless of how "ugly" some of these protection mechanisms may appear; the goal is to help (mitigate/prevent) security issues to some degree, making it difficult for an attacker. As everybody knows by now: "you cannot keep a hacker out, you can only discourage their efforts".
Tools & Requirements
The goal is to have a simple set of tools (functions):
these MUST be in plain (vanilla) javascript
together they should NOT exceed a few lines of code (at most 200)
they have to be immutable, preventing "re-capture" by an attacker
these MUST NOT clash with any (popular) JS frameworks, such as React, Angular, etc
does NOT have to be "pretty", but readable at least, "one-liners" welcome
cross-browser compatible, at least to a good percentile
Runtime Reflection / Introspection
This is a way to address some of these concerns, and I don't claim it's "the best" way (at all), it's an attempt.
If one could intercept some "exploitable" functions and methods and see if "the call" (per call) was made from the server that spawned it, or not, then this could prove useful as then we can see if the call came "from thin air" (dev-tools).
If this approach is to be taken, then first we need a function that grabs the call-stack and discard that which is not FUBU (for us by us). If the result of this function is empty, hazaa! - we did not make the call and we can proceed accordingly.
a word or two
In order to make this as short & simple as possible, the following code examples follow DRYKIS principles, which are:
don't repeat yourself, keep it simple
"less code" welcomes the adept
"too much code & comments" scare away everybody
if you can read code - go ahead and make it pretty
With that said, pardon my "short-hand", explanation will follow
first we need some constants and our stack-getter
const MAIN = window;
const VOID = (function(){}()); // paranoid
const HOST = `https://${location.host}`; // if not `https` then ... ?
const stak = function(x,a, e,s,r,h,o)
{
a=(a||''); e=(new Error('.')); s=e.stack.split('\n'); s.shift(); r=[]; h=HOSTPURL; o=['_fake_']; s.forEach((i)=>
{
if(i.indexOf(h)<0){return}; let p,c,f,l,q; q=1; p=i.trim().split(h); c=p[0].split('#').join('').split('at ').join('').trim();
c=c.split(' ')[0];if(!c){c='anon'}; o.forEach((y)=>{if(((c.indexOf(y)==0)||(c.indexOf('.'+y)>0))&&(a.indexOf(y)<0)){q=0}}); if(!q){return};
p=p[1].split(' '); f=p[0]; if(f.indexOf(':')>0){p=f.split(':'); f=p[0]}else{p=p.pop().split(':')}; if(f=='/'){return};
l=p[1]; r[r.length]=([c,f,l]).join(' ');
});
if(!isNaN(x*1)){return r[x]}; return r;
};
After cringing, bare in mind this was written "on the fly" as "proof of concept", yet tested and it works. Edit as you whish.
stak() - short explanation
the only 2 relevant arguments are the 1st 2, the rest is because .. laziness (short answer)
both arguments are optional
if the 1st arg x is a number then e.g. stack(0) returns the 1st item in the log, or undefined
if the 2nd arg a is either a string -or an array then e.g. stack(undefined, "anonymous") allows "anonymous" even though it was "omitted" in o
the rest of the code just parses the stack quickly, this should work in both webkit & gecko -based browsers (chrome & firefox)
the result is an array of strings, each string is a log-entry separated by a single space as function file line
if the domain-name is not found in a log-entry (part of filename before parsing) then it won't be in the result
by default it ignores filename / (exactly) so if you test this code, putting in a separate .js file will yield better results than in index.html (typically) -or whichever web-root mechanism is used
don't worry about _fake_ for now, it's in the jack function below
now we need some tools
bore() - get/set/rip some value of an object by string reference
const bore = function(o,k,v)
{
if(((typeof k)!='string')||(k.trim().length<1)){return}; // invalid
if(v===VOID){return (new Function("a",`return a.${k}`))(o)}; // get
if(v===null){(new Function("a",`delete a.${k}`))(o); return true}; // rip
(new Function("a","z",`a.${k}=z`))(o,v); return true; // set
};
bake() - shorthand to harden existing object properties (or define new ones)
const bake = function(o,k,v)
{
if(!o||!o.hasOwnProperty){return}; if(v==VOID){v=o[k]};
let c={enumerable:false,configurable:false,writable:false,value:v};
let r=true; try{Object.defineProperty(o,k,c);}catch(e){r=false};
return r;
};
bake & bore - rundown
These are failry self-explanatory, so, some quick examples should suffice
using bore to get a property: console.log(bore(window,"XMLHttpRequest.prototype.open"))
using bore to set a property: bore(window,"XMLHttpRequest.prototype.open",function(){return "foo"})
using bore to rip (destroy carelessly): bore(window,"XMLHttpRequest.prototype.open",null)
using bake to harden an existing property: bake(XMLHttpRequest.prototype,'open')
using bake to define a new (hard) property: bake(XMLHttpRequest.prototype,'bark',function(){return "woof!"})
intercepting functions and constructions
Now we can use all the above to our advantage as we devise a simple yet effective interceptor, by no means "perfect", but it should suffice; explanation follows:
const jack = function(k,v)
{
if(((typeof k)!='string')||!k.trim()){return}; // invalid reference
if(!!v&&((typeof v)!='function')){return}; // invalid callback func
if(!v){return this[k]}; // return existing definition, or undefined
if(k in this){this[k].list[(this[k].list.length)]=v; return}; //add
let h,n; h=k.split('.'); n=h.pop(); h=h.join('.'); // name & holder
this[k]={func:bore(MAIN,k),list:[v]}; // define new callback object
bore(MAIN,k,null); let f={[`_fake_${k}`]:function()
{
let r,j,a,z,q; j='_fake_'; r=stak(0,j); r=(r||'').split(' ')[0];
if(!r.startsWith(j)&&(r.indexOf(`.${j}`)<0)){fail(`:(`);return};
r=jack((r.split(j).pop())); a=([].slice.call(arguments));
for(let p in r.list)
{
if(!r.list.hasOwnProperty(p)||q){continue}; let i,x;
i=r.list[p].toString(); x=(new Function("y",`return {[y]:${i}}[y];`))(j);
q=x.apply(r,a); if(q==VOID){return}; if(!Array.isArray(q)){q=[q]};
z=r.func.apply(this,q);
};
return z;
}}[`_fake_${k}`];
bake(f,'name',`_fake_${k}`); bake((h?bore(MAIN,h):MAIN),n,f);
try{bore(MAIN,k).prototype=Object.create(this[k].func.prototype)}
catch(e){};
}.bind({});
jack() - explanation
it takes 2 arguments, the first as string (used to bore), the second is used as interceptor (function)
the first few comments explain a bit .. the "add" line simply adds another interceptor to the same reference
jack deposes an existing function, stows it away, then use "interceptor-functions" to replay arguments
the interceptors can either return undefined or a value, if no value is returned from any, the original function is not called
the first value returned by an interceptor is used as argument(s) to call the original and return is result to the caller/invoker
that fail(":(") is intentional; an error will be thrown if you don't have that function - only if the jack() failed.
Examples
Let's prevent eval from being used in the console -or address-bar
jack("eval",function(a){if(stak(0)){return a}; alert("having fun?")});
extensibility
If you want a DRY-er way to interface with jack, the following is tested and works well:
const hijack = function(l,f)
{
if(Array.isArray(l)){l.forEach((i)=>{jack(i,f)});return};
};
Now you can intercept in bulk, like this:
hijack(['eval','XMLHttpRequest.prototype.open'],function()
{if(stak(0)){return ([].slice.call(arguments))}; alert("gotcha!")});
A clever attacker may then use the Elements (dev-tool) to modify an attribute of some element, giving it some onclick event, then our interceptor won't catch that; however, we can use a mutation-observer and with that spy on "attribute changes". Upon attribute-change (or new-node) we can check if changes were made FUBU (or not) with our stak() check:
const watchDog=(new MutationObserver(function(l)
{
if(!stak(0)){alert("you again! :D");return};
}));
watchDog.observe(document.documentElement,{childList:true,subtree:true,attributes:true});
Conclusion
These were but a few ways of dealing with a bad problem; though I hope someone finds this useful, and please feel free to edit this answer, or post more (or alternative/better) ways of improving front-end security.
I am currently considering how to support a legacy web application in a new language(language here meaning spoken language - not code!).
I will be doing this using some form of javascript internationalisation library however I've stumbled upon an issue.
Currently the application can be driven solely by keyboard shortcuts - these short cuts are indicated to the user by underlining the letter of a function label on the screen which corresponds with a short cut.
For example:
<u>R</u>un
<u>J</u>ump
J<u>o</u>g
The problem is when these strings are replaced with tokens for internationalisation the strings are going to be stored as plain text and I would like to not have to tarnish these strings files with html tags(especially a tag which is discouraged nowadays anyway)
If we decouple logic to decide which letter to underline - which could well change with along with a language change - how could I go about underlining a single character in a string? Is it even possible?
//HTML
//Strings file
action.jump=Jump
//Javascript/JQuery
$('<someHowOnlySelectAParticularLetter('J')> #jump').css({text-decoration:overline});
function someHowOnlySelectAParticularLetter(var character){
//TODO
}
Thanks in advance for any responses - even I haven't explained the issue at hand clearly please say so and I will attempt to clarify any questions!
What letter is "active" is language-dependent, so this info has to be stored in each language specific config file (translation table file):
English:
RUN: "Run"
RUN_ACTION: "R"
French:
RUN: "Courir"
RUN_ACTION: "C"
Then use this information (and meta-infromation) to generate your HTML:
function buildAction(label, letter) {
return label.replace(letter, '<u id="action-' + letter + '">' + letter + '</u>');
}
var html = '<p>menu: ' + buildAction(RUN, RUN_ACTION) + ', ...</p>';
document.write(html);
Then you can $('#action-' + RUN_ACTION).css and $('#action-' + RUN_ACTION).click.
With this you only need to switch between translation table files.
I'd generate the HTML server-side though.
If you want to keep using that design, you're gonna run into all sorts of problems.
What if the translated word doesn't have the letter shortcut you applied to your other language?
If a user gets used to a set of shortcuts and changes the language, are all the shortcuts he is used to going to change?
For example, Ctrl+S is a widely used shortcut for Save, even if some languages don't have a S in their translation of 'Save'. Change that letter to W, which is the common shortcut for Quit, and you're in for an unpleasant user experience.
I suggest you change your markup to
(R) Run
(J) Jump
(O) Jog
That way you only need to translate the word part, and leave the shortcut as it is.
It seems that you would have to use a little bit of RegEx (regular expressions) and .split to be able to grab that letter, store it in a variable and then style it with jquery's .css method.
It is an admirable goal to separate data from presentation.
I don't think pure CSS will get you all the way there, without also having some supporting HTML markup.
You actually need the hotkey information in two places:
In the UI markup
In the code that processes key presses
I would suggest that you store the information about the hotkey in a format similar to:
// Word Hotkey Offset Function Language
// Sichern S 0 Save DE
// Springe p 1 Jump DE
(example above uses German).
Use that data to drive
Rendering of the UI (e.g. when rendering to HTML markup, wrap the character position designated by Offset with a tag of your choice that matches your CSS rules.
Have the code that captures key clicks and executes functionality use the same data.
I have a web page that the title is changed from 'Pagename' to '(1) Pagename' when there is an update on the page. That number increments to 50 each time there is a new update and then is maxed out showing '(50+) Timeline'.
When logging page views, Google Analytics shows the '(n) Pagename', which I don't want. So I found out how to manually change to logged page title, _gaq.push(["_set", "title", 'new title']);.
So my question is, how do I most efficiently remove the (1-50)/(50+) prefix and just get 'Pagename'? Is regex best for this?
This is what I'm using based on the answer from Ross:
var window_title = window.title.replace(/^\(\d+\+?\)\s/, '');
_gaq.push(["_set", "title", window_title]);
Yes, RegEx can do that.
window.title.replace(/^\(\d+\+?\)\s/, '');
Of course it depends on what software your site is using as perhaps it would be possible to just output the page title without that prefix in the relevant part of the template. So echoing that directly into the Google Analytics tag. But I think the above javascript is probably the easier solution to implement.
I'm writing a Dashboard widget in Dashcode, and on the back side, I've got a string for credits. I want to include the widget's version number in that string, but if possible, I want to programmatically grab it from the CFBundleVersion or CFBundleShortVersionString key in Info.plist to avoid having to change the number in multiple places if and when I update the widget.
Searches on Apple's developer documentation, Google and various forums have proven fruitless so far. What I'd like to know is whether there's a built-in way to do this that Apple included but forgot to mention (like var version = widget.version(); or something), or whether my script will have to pull in and parse the entire plist before plucking out the one value I actually want.
Thanks for any help you can provide!
I seem to have found the answer: use Dashcode's "data source" facility to read in Info.plist as an XML data source. From there, this blog post showed me how to traverse the plist's structure and get the correct string (in this case, the fifth <string> element in the file, corresponding to CFBundleShortVersionString.
The function I ended up with:
function getWidgetVersion() {
var dataSource = dashcode.getDataSource("infoPlist");
var version = dataSource.selection().valueForKey("dict").valueForKey("string")[4]; // This line and the previous could probably be combined for the sake of brevity
if (typeof(version) == 'string') {
document.getElementById("creditsLabel").innerHTML += version; //I'll change this to just pass the number on
}
}
Since the text of the creditsLabel div has already been started off with a localized string, I get a nice little label saying "Version 1.0".
I've got this page I'm doing some tests in Javascript and jQuery: JS Tests
I've got a few questions on how to create, not sure if this is right term, but compound controls via Javascript. In something like Flash, you'd create the Object class, have the getters and setters, draw your images, etc. In JS, it seems to be a very different thought process. My main question is How do you create multiple elements with getters and setters to be rendered, filtered, and interacted with in Javascript?
The main code regarding this example sits with:
var html = (function(){
// var FRAG = $(document.createDocumentFragment());
htmlBox = $(document.createElement("div"));
var eTitle = $(document.createElement("h4"));
var ePrice = $(document.createElement("p"));
// set class first
htmlBox.addClass("box")
htmlBox.css({
backgroundColor : color
})
// set text values
eTitle.text(title);
ePrice.text("$" + price);
htmlBox.append(eTitle)
htmlBox.append(ePrice)
return htmlBox;
})();
... inside the Box() class. If someone could take a look at the source and let me know what isn't quite right, that'd be great.
EDIT
Here's the final result for this example. Some logistics to work out, but what I'm after.
http://geerswitch.in/tests/obj/
As for the jQuery creating nodes, the built in JS version works fine for this, and some research on Google shows that the non-jquery way is faster in most cases anyway (and looks worse, imo)
You're doing it almost right. You've created a Box class to represent your higher-order UI element, you're instantiating it for each element, and your main program is manipulating the elements through its interface. The only thing you're missing is the split between the public interface and the private implementation. There's nothing to prevent me from doing myBox.price += 10 right now, even though the Box interface clearly implies that price should be set at construction and never modified.
JavaScript doesn't have visibility modifiers like "private" and "public", but you can create the same effect yourself. Check out Douglas Crockford's explanation for the details. Crockford is an opinionated genius when it comes to JavaScript, and he's the brains behind JSLint and JSON.