Is there a norm for AJAX security?
When making an XMLHttpRequest, if querying an HTTPS url, will the browser handle all the certificate business and properly encrypt the request (or use an already existing authenticated tunnel)? Are there any security flaws in this model?
Then there's also user authentication issues with AJAX. This made me think that using the user's password to encrypt part or all of an AJAX request could solve some authentication issues. I've seen some impressive javascript based encryption tools. It seems like there'd be lots of potential there to build a single system that takes care of both encryption and authentication(host level and application user level). I have however not seen anything that seems 'tried an true'.
My question can be summed up as:
Is there a norm for secure AJAX either
using browser technologies or client
side javascript? What
is it? And if not, what's preventing
us from building one using javascript?
Thank you, as always.
SSL through HTTPS is sort of a cooperative venture with the destination server. The destination server will report its identity with its identity certificate (sent back to the client). This is part of the protocol that will encrypt the data stream between the client and the server.
However, this just encrypts the stream, it does nothing about several other security issues. Identification and authentication of the user entity making a request is handled through other means. If you're encrypting the stream with SSL, it should be safe to use HTTP basic auth. After that, the response to authentication should be a session id sent back to the client that will pass it back on all subsequent requests. Application servers typically manage the creation of those session ids.
Ajax does not inherently introduce new
security vulnerabilities in the realm
of web applications. Instead, the
applications face the same security
issues as classic web applications.
Unfortunately, common Ajax best
practices have not been developed,
which leaves plenty of room to get
things wrong.
from: http://www.securityfocus.com/infocus/1868
Basic authentication makes sense. I found this article explaining how to do it.
I somehow still have this desire to not use all the browser technologies and encrypt/authenticate things myself. Not sure if that would make any sense. Key caching would be hard to accomplish.
I'm still looking to find out if this (SSL + using basic auth in ajax calls) is the norm.
Related
I have a problem that people are cloning my website front and imitate calls to my API from their own domains to abuse my service. The solution I came up with is for Angular client to check the URL it works on, encrypt it and add as a header to API call. Obfuscate the JS code to prevent reverse engineering. This way API will receive an encrypted header and make sure that the domain is the proper one.
So on the client side
headers.append(`CustomHeader`, this.encryptDomain());
and on the server side
var domainEncrypted = Request.Content?.Headers?.GetValues("CustomHeader").FirstOrDefault();
var domainPlain = Decrypt(domainEncrypted);
if (domainPlain != myDomain)
{
return BadRequest();
}
Can you please help me with code samples to match JS and C# encrypt and decrypt algorithms? So that encryptDomain works on JS side and Decrypt works on the C# side. I am aware that this is not a perfect solution, but I want to try. And if anyone has a better idea, you are welcome.
Edit: apparently what I want to do is similar to JScrambler domain lock feature
TLDR
It is not possible to prevent communicate with your API through different (cloned) clients guaranteed way in cases when white-lists of IP addresses can't/shouldn't be used.
Why
Think about it that way. You have a server that has some identification rule - client should have some identifier that marks it as trusted. In your question it is a domain.
Domain is a public information that could be passed in HTTP header or in the body of your request, it is easy, but also it will be easy for clients to replace this information on their side.
And if you use any type of cryptography to provide more secured identification mechanism - you just making it harder to hack it and again pretend as trusted client, because every mechanism you use on the client side could be reverse-engineered by a hacker. Just look at this question.
One think you can use to guaranteed access restriction is to use white-list of IP addresses on server-side, because IP address is a part of TCP/IP transport level protocol and it has "handshake" process to identify communicated points to each other, and it is kind of hard to replace it. Check this question for details.
So what can you do?
CORS
Setup CORS policy is a first step to create a trusted client-server communication. Most of browsers are support CORS policies, but of course client may be not a browser. And the questions was not about browser-server communication, but I should mention that because browser is a client too.
Client-side encryption
You can use encryption, but I don't see any reason to do that because any request to server could be read through your legal client (website). So even if you encrypted it - any person has a key and a crypto algorithm on their side to pretend as trusted client. But if you want to...
You need to create unique key every your request to make life of pretenders little harder. To make it you need few ingredients:
Public key for key generation (encrypted) on the client side
Obfuscated key generation JS code
Private key for decrypt generated key on the server side
JS-side RSA crypto libraries could be googled easily (for example)
Obfuscation libraries could be found just using google too (like this)
Server-side decryption could be done with System.Security.Cryptography namespace if you use C# backend.
Basically, more complex key-generation algorithm you make and more obfuscated code you make - more hard for hacker to pretend himself as a trusted client. But as I said there is no guaranteed way to completely identify trusted client.
You cannot prevent people from copying your website's FE assets... They are supposed to be publicly available. You could try to make it a little harder by spliting your built app in more chunks (with angular's lazzy-loading or by manipulating webpack's config). Still, Browsers require code in plain text, so although this makes it a little harder it does not prevent copying.
When we build angular for production it already does code obfuscation through its optimizations (minification, tree-shaking and so on).
To mitigate the problem of people misusing your Server resources, you need to implement robust practices on Back-End request authorization and some miss-usage detection.
Configuring CORS would not work, as you reported attackers are using BE proxies.
Make sure your request's authentication is solid. A market standard approach is the use of a JWT payload embedded in the Authorization Header of each request. It is simple, reliable and resource-inexpensive.
I would also recommend the implementation of request throttling. But this is a separated question.
If your authentication is already solid, you would need to detect when your real users are misusing your system. There are many tools to monitor traffic (like azure's) but there is no umbrella definition for "unusual traffic". Detection of "unusual traffic" is what you would need to custom built for the specifics of your system. Once you have a network traffic tool in place that should help you getting started.
Couple of solutions for you. Firstly you can block by applying a CORS policy on server. If you still want to do from code then you can block on this basis of hostname in c# like this.
var hostname = requestContext.HttpContext.Request.Url.Host;
if (hostname != myDomain)
{
return BadRequest();
}
This is a design question for AngularJS websites that access a REST API. Since all the AngularJS code can be viewed from the client side (assuming obfuscation is not completely secure) how do you hide the API access credentials (the API key and password or even a JWT)?
This can be extended to a broader question about how other application logic can be hidden in an AngularJS website?
My research led me to some insights, one of which was
http://billpatrianakos.me/blog/2016/02/15/securing-api-keys-in-a-javascript-single-page-app/
But this has me more confused now, since the post suggests an SPA connecting to a REST API is not a good architecture. I thought it was and now can't figure what the right approach is.
The closest I can come to an answer is this resource:
https://developers.facebook.com/docs/facebook-login/security#appsecret
Facebook, is pretty good with their security and say:
Never include your App Secret in client-side or decompilable code.
Use unique short-term tokens on clients.
In short, do not keep API secrets on the client side
Answering the discussion in comments for sake of not being brief:
And then my question would be "what then is the correct architecture for SPAs and server side code (or database access)?".
There's no one correct architecture, it depends on the size and scope of your project. It will also depend on what frontend and backend frameworks you choose. Those choices also will depend on how many other APIs you are calling, or what other developers or you are most familiar with.
Speaking more specifically about security though, ideally you'd like to set up a session for the user which consists of a token that the user uses to identify himself. This is usually generated for each user by the server when they login. Generally this is provided by the framework you are working in, but even if it isn't, it's fairly simple to build. You will want to prevent cross origin requests (making sure the user is actually on YOUR frontend) and have secure connections (setting up SSL and https, though this can get complicated). You will generally want to run your JS code through something like Uglify to prevent it from being too easy to look through, but this does NOT guarantee that people cannot take that code and un-uglify it.
As the other answers have suggested, you should never keep API keys or any secrets in the client source code. There is no way to hide anything on the client, and obfuscation != security.
If you are looking to architect secure authentication/authorization into your app, you will want to return a JWT to the AngularJS application. You can then pass this JWT as a Bearer token to your API which will verify the validity of the token and allow the API to authorize access to the AngularJS application.
As for where to store the JWT token, you can store it in either Local Storage or in a cookie. There are serious considerations between choosing whether to store the token in either of these locations.
If security is your concern, I would look into the OAuth 2.0 Implicit Flow.
Don't put API keys in your client side source code. Keep them on your server, and have your client make a request to YOUR server, which then calls out to external APIs for data.
Hello I am going to be switching from using googles Client-side flow to the
Hybrid server-side flow because before the client would be sent a access_token which I was then going to send to the server to then verify the user before logging them in or creating a new account for them but since I can't get cors to work with https, I can not safely send it.
I looked over the different ways and it seems the Hybrid server-side flow is the one I wanted all along anyways, the only question I have is, is it safe to send the one time authorization code over http using ajax?
I figure it is since it is only usable once and once the server uses it which would be over https using curl, it no longer has any value anyways. The access_token would then only ever be on the server and never have been on the client which seems much more secure then the old way of using the client side flow.
The short answer is: absolutely not
The longer answer depends on level of risk and what risk you're willing to accept, but in general it seems like a bad idea. It assumes that the either the connection between client and server has a low chance of being intercepted or manipulated, or that the information being protected by oauth is of incredibly low value that nobody would ever try. Neither of these seem like safe prospects.
For example, and purely offhand, it would not be difficult for a rogue router in between client and server to intercept the request (if it knew about the likelihood of it) and use the client code itself first. This could cause all sorts of problems on both your server and client which could take a while to resolve... during which the rogue has access to whatever service was being authorized. There are other scenarios, similar to this one, which could be equally problematic.
The better question is - why do you want to do this? Is there a reason you're not willing to setup an SSL server, even one with a self-signed certificate?
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.
It's not that I don't have access to javascript, of course. In most of my CS Web Development courses, we are taught a little bit about server-side validation, and then as soon as javascript is introduced, server-side validation is thrown out the window.
I choose not to just rely on javascript, as the client-side is never a secure place. I have gotten into the habit of writing both the client and server-side code for such things. However, for a web application that I am writing that has optional AJAX, I do not want the password to be send plaintext over the wire if someone has javascript turned off.
I realize I may be asking a catch-22 situation, so let me just ask this: how do we know our users' passwords will be secure (enough) from malicious users on the same network when all we can rely on is server-side scripting. On that first request from the login page, is there any way to have the browser encrypt a data field?
SSL Solves this problem. For the record, passwords should never be "encrypted" or "encoded", this employs that there is a method of "Decoding" or "Decrypting" which is a clear violation if CWE-257. Passwords must be hashed, SHA-256 is a great choice, but this is not meant for transmission, only storage. When you transit secrets there is a long list of things that can go wrong, SSL is by far the best choice for solving these issues.
If the attacker can sniff the traffic then they will be able to see the session id and use it immediately, so its a moot point. You have to use SSL to protect the authenticated session anyway.
The easy solution is SSL.
I think you're mixing up a couple of concepts. The browser does not encrypt individual fields. Client-side scripting, server-side scripting and AJAX are not means to defend against eavesdropping.
As others have said, SSL is the technology that encrypts the data. The entire request and response, including the fields and scripts are contained within the SSL session.
You can also use Digest HTTP Authentication.