Here's the idea:
If I can get something unique about a computer with JavaScript from an HTML page (probably the MAC address), then can I use this data as another security check?
Is that possible?
I am not going to check the computer at client side, i am going to send it to server to check. If nothing sent, user will be blocked. So it is not something that any developer+firebug combination can bypass. I just want to send one more string with username and password which is unique to computer and no one else knows if they don't entered to the system from that computer. Like a password hidden from user itself.
You can try using a tracking cookie; note however that such mechanisms are considered transient (e.g. cookies can be erased). In-browser JavaScript is sandboxed so that it does not have access to components outside the page. Note also that any feeling of security you'll gain with JavaScript is illusory - the script runs on the client side, where it can be modified (therefore there's no way to tell whether the "unique" piece of data is genuine or faked) or disabled altogether.
If you're trying to prevent random people from hacking at your app, you may want to ban them after a certain number of failed attempts. This will not get you any security, it's more of a flytrap - it limits the annoyances somewhat.
Finally, if you want actual security, go for HTTPS with real (NOT self-signed) server certificates and client-side certificates - see e.g. this for an implementation (that example, however, uses self-signed server certificates, which is not very secure). This is a mechanism that is well-implemented in the browser itself, and provides you with a somewhat secure system (complete with a secure keystore) of identifying your users (as opposed to a fundamentally flawed JS "security", or relying on user-readable files). Oh, and your data is encrypted while on the wire, that's a bonus.
SSL actually does what you're asking for: verifies that the client machine has a certificate issued to that user. This mechanism works inside the browser, not just inside the webpage; thus, it is much harder to subvert this than an in-page JavaScript. It stores a large unique identifier (clientside certificate) in a secure way, and it can prove to the server that it actually has that identifier - which is pretty much your initial requirement.
(Incidentally, using SSL, the data will be protected in transit, and the client can validate the server's identity; those weren't your requirements, but they're more or less necessary to assure that you're actually talking to the real client and real server)
JavaScript within a Web browser executes within a sandbox and has no access to the underlying hardware. Besides, MAC addresses aren't guaranteed to be unique.
No. And you shouldn't implement security with JavaScript only as any competent developer with Firebug will get around it in no time.
Related
I'm curious if there's any way that a server can validate a client without knowing that the client is entirely "friendly" code that isn't monitoring 1) the user's input or 2) network requests.
The only way I could conceive of this is if browsers have a built-in, secure, isolated shell / scope that can hash and send data (which can be verified with a complimenting server unhashing / lookup script).
Is there any browser-supported (non-DOM) input/hashing method that can also be installed on the server to identify the authenticity or user input? I want to avoid Chrome Extensions and potential keylogging in general, but I'm not sure any browser supports this feature.
Thanks
EDIT
I think some form of 2-step auth in a separate window would be the closest, but I don't have SSL, and I don't like the presentation of random "popup" windows
If I understand your question correctly you are asking for a proof that the data entered into a form are neither manipulated nor generated by malicious software. But you (as operator of the server) don't have control of the client.
This is impossible as long as you don't have control of the client because it is impossible to distinguish user generated data from software generated data on the network level, and that's all you get at the server. Even the output generated by a browser extension can be faked.
I think some form of 2-step auth would be the closest
2FA is relevant for authentication of the client only and provides no way of making user generated data tamper resistant.
SSL alternative for secure handshake?
SSL only protects the transport and does not prevent modification of the user input within a malicious browser extension or similar. It also does not protect against malicious man in the middle on the clients machine (i.e. Superfish or similar).
As part of a thought experiment, I am attempting to ascertain whether there is any hope in a server providing a piece of data only for receipt and use by a browser environment, i.e. which could not be read by a bot crawling my site.
Clearly, if that information is sent in the source code, or indeed via any usual HTTP means, this can be picked up by a bot - so far, so simple.
But what about if the information was transmitted by the server instead as a websocket message: Wouldn't this be receivable only by some corresponding (and possibly authenticated) JavaScript in the browser environment, thus precluding its interception by a bot?
(This is based on my assumption that a bot has no client environment and is essentially a malicious server-side script calling a site over something like cURL, pretending to be a user).
Another way of phrasing this question might be: with the web implementation of websockets, is the receipt of messages always done by a client environment (i.e. JS)?
I can't answer about websockets, but a sufficiently motivated attacker will find a way to emulate whatever environment you require. By loading this content through ajax, you can eliminate the casual bots. You can eliminate well behaved bots with robots.txt.
Using WebSocket makes no difference. You cannot escape the following fact: you can always write a non-browser client that looks and behaves to the server exactly as any standard browser.
I can fake: any HTTP headers (like browser vendor etc) you might read. The origin header doesn't help either (I can fake it). Neither does cookies. I'll read them and give it back.
You might get away by protecting your site with strong captchas, and set cookies only after the captcha was solved. That depends on the captcha being unsolvable by bots ..
I'm looking forward to start using Ember.js in a real life project, but as someone coming from a Java background, I always care about Security.
And when I say to my fellow Java developers, I start using a JavaScript MVC, they start saying it's not secure enough, as JavaScript is all about client-side there is always a way to hack around your JavaScript code, and know backdoors to your services and APIs.
So is there any good practice that can help prevent this kind of attacks, or at least trying to make it less effective?
There is always a way to hack around your javascript code, and know backdoors to your services and APIs.
JavaScript presents few new problems for services and APIs that are already exposed to the web. Your server/service shouldn't blindly trust requests from the web, so using javascript doesn't alter your security posture, but it can lull people into a false sense of security by making them think they control the user-agent.
The basic rule of client/server security is still the same: don't trust the user-agent ; place the server and the client on different sides of a trust boundary.
A trust boundary can be thought of as line drawn through a program. On one side of the line, data is untrusted. On the other side of the line, data is assumed to be trustworthy. The purpose of validation logic is to allow data to safely cross the trust boundary--to move from untrusted to trusted.
Validate everything that the server receives from the client, and, because XSS vulnerabilities are common and allow clients to access information sent to the client, send as little sensitive information to the client as possible.
When you do need to round-trip data from the server to the client and back, you can use a variety of techiniques.
Cryptographically sign the data so that the server can verify that it was not tampered with.
Store the data in a side-table and only send an opaque, unguessable identifier.
When you do need to send sensitive data to the client, you also have a variety of strategies:
Store the data in HTTP-only cookies which get attached to requests but which are not readable by JavaScript
Divide your client into iframes on separate origins, and sequester the sensitive information in an iframe that is especially carefully reviewed, and has minimal excess functionality.
Signing
Signing solves the problem of verifying that data you received from an untrusted source is data that you previously verified. It does not solve the problem of eavesdropping (for that you need encryption) or of a client that decides not to return data or that decides to substituting different data signed with the same key.
Cryptographic signing of "pass-through" data is explained well by the Django docs which also outline how their APIs can be used.
The golden rule of Web application security is to never trust data from untrusted sources. Sometimes it can be useful to pass data through an untrusted medium. Cryptographically signed values can be passed through an untrusted channel safe in the knowledge that any tampering will be detected.
Django provides both a low-level API for signing values and a high-level API for setting and reading signed cookies, one of the most common uses of signing in Web applications.
You may also find signing useful for the following:
Generating “recover my account” URLs for sending to users who have lost their password.
Ensuring data stored in hidden form fields has not been tampered with.
Generating one-time secret URLs for allowing temporary access to a protected resource, for example a downloadable file that a user has paid for.
Opaque Identifiers
Opaque identifiers and side tables solve the same problem as signing, but require server-side storage, and requires that the machine that stored the data have access to the same DB as the machine that receives the identifier back.
Side tables with opaque, unguessable, identifiers can be easily understood by looking at this diagram
Server DB Table
+--------------------+---------------------+
| Opaque Primary Key | Sensitive Info |
+--------------------+---------------------+
| ZXu4288a37b29AA084 | The king is a fink! |
| ... | ... |
+--------------------+---------------------+
You generate the key using a random or secure pseudo-random number generator and send the key to the client.
If the client has the key, all they know is that they possess a random number, and possibly that it is the same as some other random number they received from you, but cannot derive content from it.
If they tamper (send back a different key) then that will not be in your table (with very high likelihood) so you will have detected tampering.
If you send multiple keys to the same misbehaving client, they can of course substitute one for the other.
HTTP-only cookies
When you're sending a per-user-agent secret that you don't want it to accidentally leak to other user-agents, then HTTP-only cookies are a good option.
If the HttpOnly flag (optional) is included in the HTTP response header, the cookie cannot be accessed through client side script (again if the browser supports this flag). As a result, even if a cross-site scripting (XSS) flaw exists, and a user accidentally accesses a link that exploits this flaw, the browser (primarily Internet Explorer) will not reveal the cookie to a third party.
HttpOnly cookies are widely supported on modern browsers.
Sequestered iframes
Dividing your application into multiple iframes is the best current way to allow your rich client to manipulate sensitive data while minimizing the risk of accidental leakage.
The basic idea is to have small programs (secure kernels) within a larger program so that your security sensitive code can be more carefully reviewed than the program as a whole. This is the same way that qmail's cooperating suspicious processes worked.
Security Pattern: Compartmentalization [VM02]
Problem
A security failure in one part of a system allows
another part of the system to be exploited.
Solution
Put each part in a separate security domain. Even when
the security of one part is compromised, the other parts
remain secure.
"Cross-frame communication the HTML5 way" explains how iframes can communicate. Since they're on different domains, the security sensitive iframe knows that code on other domains can only communicate with it through these narrow channels.
HTML allows you to embed one web page inside another, in the element. They remain essentially separated. The container web site is only allowed to talk to its web server, and the iframe is only allowed to talk to its originating server. Furthermore, because they have different origins, the browser disallows any contact between the two frames. That includes function calls, and variable accesses.
But what if you want to get some data in between the two separate windows? For example, a zwibbler document might be a megabyte long when converted to a string. I want the containing web page to be able to get a copy of that string when it wants, so it can save it. Also, it should be able to access the saved PDF, PNG, or SVG image that the user produces. HTML5 provides a restricted way to communicate between different frames of the same window, called window.postMessage().
Now the security-sensitive frame can use standard verification techniques to vet data from the (possibly-compromised) less-sensitive frame.
You can have a large group of programmers working efficiently at producing a great application, while a much smaller group works on making sure that the sensitive data is properly handled.
Some downsides:
Starting up an application is more complex because there is no single "load" event.
Iframe communication requires passing strings that need to be parsed, so the security-sensitive frame still needs to use secure parsing methods (no eval of the string from postMessage.)
Iframes are rectangular, so if the security-sensitive frame needs to present a UI, then it might not easily fit neatly into the larger application's UI.
Cryptico seems like a super slick RSA encryption library.
cryptico.wwwtyro.net
In regards to JavaScript applications, suppose I want to send data to the client, have them do something to the data, and pass it back. How can I use RSA to ensure that the data clients send back to the server is not tampered with? Since JavaScript is easily reverse-engineered, is there any practical client-side application of cryptico?
Do you - by your example - mean that you want to hide from the user what his client is doing with the data? If so - it's impossible.
You should never trust any data which comes from the client.
If you send encrypted data to the client to process - you must assume that the user knows (or will know if he wants) the encryption key, otherwise it will be impossible to process. In other words there is no secure way to hide from the user what his client processes. Obfuscation - like you've noticed can always be cracked no matter what language you use.
I think that the most common and practical client-side application for this library would be encrypting user's data and sending them to server or vice-versa. There may be some cases you can't use SSL. Moreover, you can make -for example- an encrypted post on facebook which only your friend will be able to decrypt (because he knows the key).
There is a solution to what you seek (I'm sure there is more than one). My answer requires two non-conventional approaches to what we call a 'secure connection' and how you receive the 'client code'.
You need a physically pre-shared key that initiates a secure connection, and because it's pre-shared it doesn't have to be RSA, which then opens up speed opportunities and higher levels of encryption security for you.
Physically pre-share your client code in a similar manner, i.e., download the code from a cd in a magazine or from a pre-paid card sold in a market. This stops the MITM from sending you tampered and exploited clients, which ssl allows. Once client is known to be secure, and a real secure connection, mentioned in (1), is established, the client code can be updated.
With the combination of a pre-shared key that develops a secure connection and client code that can pass a checksum, you can achieve what you are after.
Ideally, we should have pre-shared secure connection keys available in the market now, but we don't. So, for you to do it alone, would require to implement something similar for you website specifically until people in this country get their act together with some real security. You would have to give them keys over your phone, through the mail, etc. And your client code would most likely have to be a browser extension to install it due to cross domain security issues.
How can a user, using one of the major modern browsers, know for sure that he is running my unmodified javascript code even over an untrusted network?
Here is some more info about my situation:
I have a web application that deals with private information.
The login process is an implementation of a password-authenticated key agreement in JavaScript. Basically during login, a shared secret key is established between the client and the server. Once the user logs in all communication with the server is encrypted using the shared key. The system must be safe against ACTIVE man-in-the-middle attacks.
Assuming that my implementation is correct and the user is smart enough not to fall victim to a phishing attack there remains just one large hole in the system: an attacker can tamper with my application as it is being downloaded and inject code that steals the password. Basically the entire system relies on the fact that the user can trust the code running on his machine.
I want something similar to signed applets but I would prefer a pure javascript solution, if possible.
Maybe I am misunderstanding your problem, but my first thought is to use SSL. It is designed to ensure that you're talking to the server you think you are, and that no one has modified the content midstream. You do not even have to trust the network in this case, because of the nature of SSL.
The good thing about this approach is that you can fairly easily drop it into your existing web application. In most cases, you can basically configure your HTTP server to use SSL, and change your http:// requests to https://.
This is an old, open question but the answers seemed to not do this justice.
https:// provides integrity, not true identification nor non-repudiation.
I direct you to http://www.matasano.com/articles/javascript-cryptography/
Don't do crypto in JS, because a malicious injected script can easily grab passwords or alter the library. SJCL is neat, but it offer a blatantly false sense of security (their quote, and quoted by above)
Unfortunately, this is not as great as in desktop applications
because it is not feasible to completely protect against code
injection, malicious servers and side-channel attacks.
The long-term issue is that JavaScript lacks:
Uniformly working const
The ability to make objects deeply const and not reprototypable.
Code-signing
// codesign: cert:(hex fingerprint) signature:(hex MAC)
Certs would be managed similar to CA certs. MAC would be used with appropriate sign/verify constructions.
Crypto, clipboard stuff are reasons to have JavaScript native plugins (signed, of course)
Getting JavaScript engines to all implement a standard is another thing, but it's doable an it's absolutely necessary to end a large swath of malware.
You could have an external Javascript file which takes an MD5 hash of your login JS, and sends an Ajax request to the server to verify that it is correct and up-to-date. Use basic security or encryption practices here - public/private keys or some other method to be sure that the response came from your server.
You can then confidently display to the user that the client-side scripts are verified, and allow the login script to proceed.