I have an ASP.NET website that heavily uses JSON services. The basic structure is: jQuery Plugins -> JSON Service -> Server-Side BAL.
But, this solution is obviously not secure, since a malicious user can run a tool such as Fiddler and capture JSON calls on their machine, then replay these JSON calls changing parameters, etc.
If I were to put the web services folder under SSL, what protections would it give me? I tried putting the entire site under SSL, but still running Fiddler I can see clear-text messages going to HTTPS protocol, and I can replay those messages from Fiddler with the same or changed parameters.
I obviously have little knowledge about SSL and need some help. Does it sound like my SSL is not setup correctly, or being able to see SSL traffic via Fiddler is expected? If the latter, what protection does SSL provide in my scenario?
Thank you.
SSL only encrypts the transport. Meaning a third party cannot eavesdrop on the data exchange between the client and your server. It does not add any security features to the server or service itself.
What you need is a proper authentication, permission and validation system. Every request needs to be checked for its validity. Be prepared to receive any sort of request with any sort of parameters, be that because the user fiddled with the parameters, because of a bug in your code or whatever. If a request is invalid, meaning if a particular user is not allowed to do a certain thing, reject the request.
This is not some addon technology you can implement, it's a core design consideration of your service.
If Bob implements SSL on his website, then when Alice uses the site, then Mallory will not be able to intercept the data or alter it in-flight. SSL keeps messages between Alice's browser and Bob's server secret. It does not keep messages between Alice and Alice's browser secret.
There are two approaches you can take to protect yourself from malicious data.
Escape (or the equivalent) everything before inserting it into a different format. e.g. use prepared statements on SQL, build JSON with a JSON serializer and not string mashing, etc.
Authenticate users and only accept data from those that you trust
I am using nodejs to write an image upload service. Paying clients will be able to send an image file to my endpoint that I have set up on my server. However, when every request comes in, I need to confirm that it is actually a paying client making the request. I thought about having the client give me their domain name and I would just check the referer header. However, someone could easily spoof the referer header and use my service without paying. How do SaaS developers face this technical problem? Is it possible to fix this without requiring my clients to have some server side code?
Are you building an external image hosting service for websites or is it to share something that HAS to be private and SECURE? If it is the former then read ahead.
Of course, the header can be spoofed. Here's why you should not worry about it:
Alternative is ugly: To build a secure provisioning service, you will have to develop some kind of token system that the website owner implements at his end as well. Chances are, he would not sign up with you because there are simpler alternatives available.
Spoofing will have to be done on client side. Very few "users" will actually do this. Two geeks spoofing headers on their own machine will not make a big difference to you. If they write some proxy or middle ware that does this work automatically and many people start using it, it could be a problem. However this is not very likely.
Guess you already know, but since you haven't mentioned - it is called Hotlinking. Google this topic to find more resources.
You cannot authenticate a browser with a referrer header.
If you want to authenticate an individual, then you will likely need a login system that they provide credentials to (username/pwd) and you check those against your allowed user base. If they pass, then you set a certain type of cookie in the browser that indicates they are a legit user. Subsequent requests from this user will contain that cookie which you can check on every request.
The cookie needs to be something that you create that you can verify that cannot easily be guessed or forged (like a session or an encrypted token from your server). You would typically set an expiration on the cookie after some time period of time so that the user has to login again.
Some of the guys here are developing an application which incorporates some 'secure areas' accessible by logging in. In the past, the login form and subsequent 'secure' pages were all plain text transmitted over http, as it's an application that goes out for use on shared servers where there is little chance of being able to use SSL (think WordPress and the like). Most people just shrugged their shoulders as that's all they expected - it's hardly a national bank.
We are now thinking of writing the next version using a JavaScript front end, with the advantage of loading all the images & CSS once, then writing HTML into the DOM thereafter with extJS (or maybe jQuery). We'd like to encrypt user input at the client before being sent to the server, then decrypt server output at the browser before being rendered to HTML so as to introduce some sort of security for users. There are also gains to be had with reducing page loading times, as we're only sending gzipped JSON back and forth.
While playing around, we realised that the method we were looking at to encrypt the basic stuff also doubled up as an authentication mechanism for login in the first place.
For simplicity...:
The user connects to the login page over standard http, where the browser downloads the JavaScript package containing the hashing and encryption algorithms (SHA-256 and AES for example).
User enters username, password and secret into a login form.
The browser JavaScript sends a hash of username and password to the server via AJAX. The secret is only stored in JavaScript and is never sent across the internet.
The server looks up the hash and retrieves username and secret from the database.
The server sends a hash (same algorithm as the browser) of username and secret back to the browser.
The browser JavaScript creates a hash of username and secret and compares it to the hash sent back from the server.
If they are the same, the browser JavaScript encrypts response with secret and sends the message back to the server.
The server decrypts the message with secret to find the expected response and starts a new session.
Subsequent communications are encrypted and decrypted both ways with secret.
There seem to be a few advantages of this type of system, but are we right in thinking:
The user knows they are talking to their server if the server manages to create a hash of username and secret, proving the server knows and understands username and secret.
The server knows the user is genuine if they manage to encrypt response with secret, proving the user knows secret.
At no time is secret ever transmitted in plain text, or is it possible to determine secret from the hash.
A sniffer will only ever find out the 'secure' URL and detect compressed hashes and encryptions in the query string. If they send a request to to the URL that is malformed, no response is given. If they somehow manage to guess an appropriate request, they still have to be able to decrypt it.
It all seems quick enough as to be imperceptible to the user. Can anyone see through this, as we all just assumed we shouldn't be playing with JavaScript encryption!
Don't do this. Please use SSL/TLS. See Javascript Cryptography Considered Harmful.
If you can provide a single SSL site to deliver your JavaScript securely (to avoid the attack mentioned above), then you can use the opensource Forge library to provide cross-domain TLS connections to your other sites after generating self-signed certificates for them. The Forge library also provides other basic crypto stuff if you opt to go in a different direction. Forge has an XMLHttpRequest wrapper that is nearly all JavaScript, with a small piece that leverages Flash's socket API to enable cross-domain communication.
http://digitalbazaar.com/2010/07/20/javascript-tls-1/
https://github.com/digitalbazaar/forge
My security knowledge is kind of limited but I might learn something.I´m planning to create an ajax application where I encrypt/decrypt passwords client-side with a typed master password
using a javascript AES library and then send/retrieve the encrypted data to/from Google App Engine(user authenticated). I actually found a project with the same idea: http://code.google.com/p/safety-vault/
In my mind as long as I keep my local computer secure (keyloggers) this should be quite secure or am I missing something?
As long as you use SSL for the webapp, this should be fine. Without SSL, an attacker could modify the page to insert some Javascript that sends them your password when you type it.
You might want to reconsider your threat model, though. Do you trust the server? If not, you shouldn't trust it to not send you a page that captures your master password when you enter it. If you do, you shouldn't have any qualms in sending your master password to the server.
There is a problem here, as I assume at some point you're going to have to send your master password to the browser client? If you have the master password, then you can decrypt the stream you send...
Use HTTPS, it's what it was designed for.
You effectively are trusting Google App Engine employees, and transitively, the entire trust chain behind them, to not steal your passwords. Encrypting client side doesn't mean anything if you are executing JavaScript code the server sends you, furthermore if you have no HTTPS implemented properly, it's trivial for someone to do a man in the middle attack and steal your passwords as they are transmitted. Just store the passwords locally or encrypt them with a well known tool like GPG and upload them.
I am using the basic-auth twitter API (no longer available) to integrate twitter with my blog's commenting system. The problem with this and many other web APIs out there is that they require the user's username and password to do anything useful. I don't want to deal with the hassle and cost of installing a SSL certificate, but I also don't want passwords passed over the wire in clear text.
I guess my general question is: How can I send sensitive data over an insecure channel?
This is my current solution and I'd like to know if there are any holes in it:
Generate a random key on the server (I'm using php).
Save the key in a session and also output the key in a javascript variable.
On form submit, use Triple DES in javascript with the key to encrypt the password.
On the server, decrypt the password using the key from the session and then destroy the session.
The end result is that only the encrypted password is sent over the wire and the key is only used once and never sent with the password. Problem solved?
Generate a random key on the server (I'm using php).
Save the key in a session and also output the key in a javascript variable.
On form submit, use Triple DES in javascript with the key to encrypt the password.
This avoids sending the password in the clear over the wire, but it requires you to send the key in the clear over the wire, which would allow anyone eavesdropping to decode the password.
It's been said before and I'll say it again: don't try to make up your own cryptographic protocols! There are established protocols out there for this kind of thing that have been created, peer reviewed, beat on, hacked on, poked and prodded by professionals, use them! No one person is going to be able to come up with something better than the entire cryptographic and security community working together.
Your method has a flaw - if someone were to intercept the transmission of the key to the user and the user's encrypted reply they could decrypt the reply and obtain the username/password of the user.
However, there is a way to securely send information over an unsecure medium so long as the information is not capable of being modified in transit known as the Diffie-Hellman algorithm. Basically two parties are able to compute the shared key used to encrypt the data based on their conversations - yet an observer does not have enough information to deduce the key.
Setting up the conversation between the client and the server can be tricky though, and much more time consuming than simply applying SSL to your site. You don't even have to pay for it - you can generate a self-signed certificate that provides the necessary encryption. This won't protect against man-in-the-middle attacks, but neither will the Diffie-Hellman algorithm.
You don't have to have a certificate on your server; it's up to the client whether they are willing to talk to an unauthenticated server. Key agreement can still be performed to establish a private channel. It wouldn't be safe to send private credentials to an unauthenticated server though, which is why you don't see SSL used this way in practice.
To answer your general question: you just send it. I think your real general question is: “How do I send sensitive data over an insecure channel—and keep it secure?” You can't.
It sounds like you've decided that security isn't worth the $10–20 per month a certificate would cost, and to protect Twitter passwords, that's probably true. So, why spend time to provide the illusion of security? Just make it clear to your users that their password will be sent in the clear and let them make their own choice.
So how is this any more secure? Even though you might have secured browser<>your server, what about the rest of the Internet (your server<>twitter)?
IMHO, it's unacceptable to ask for a username and password of another service and expect people to enter that. And if you care that much - don't integrate them until they get their act straight and re-enable OAuth. (They supported it for a while, but disabled it a few months ago.)
In the mean time, why not offer OpenID? Every Google, Yahoo!, VOX etc. account has one. People might not be aware of it but chances are really, really high that they already have OpenID. Check this list to see what I mean.
When the key is sent between the client and the server it is clear text and subject to interception. Combine that with the encrypted text of the password and the password is decrypted.
Diffie-Hellman is a good solution. If you only need to authenticate them, and not actually transmit the password (because the password is already stored on the server) then you can use HTTP Digest Authentication, or some variation there of.
APIs and OAuth
Firstly, as others have said, you shouldn't be using a user's password to access the API, you should be getting an OAuth token. This will allow you to act on that user's behalf without needing their password. This is a common approach used by many APIs.
Key Exchange
If you need to solve the more general problem of exchanging information over insecure connections, there are several key exchange protocols as mentioned by other answers.
In general key exchange algorithms are secure from eavesdroppers, but because they do not authenticate the identity of the users, they are vulnerable to man-in-the-middle attacks.
From the Wikipedia page on Diffie Hellman:
In the original description, the
Diffie–Hellman exchange by itself does not provide authentication of
the communicating parties and is thus vulnerable to a
man-in-the-middle attack. A person in the middle may establish two
distinct Diffie–Hellman key exchanges, one with Alice and the other
with Bob, effectively masquerading as Alice to Bob, and vice versa,
allowing the attacker to decrypt (and read or store) then re-encrypt
the messages passed between them. A method to authenticate the
communicating parties to each other is generally needed to prevent
this type of attack. Variants of Diffie-Hellman, such as STS, may be
used instead to avoid these types of attacks.
Even STS is insecure in some cases where an attacker is able to insert their own identity (signing key) in place of either the sender or receiver.
Identity and Authentication
This is exactly the problem SSL is designed to solve, by establishing a hierarchy of 'trusted' signing authorities which have in theory verified who owns a domain name, etc, someone connecting to a website can verify that they are indeed communicating with that domain's server, and not with a man-in-the-middle who has placed themselves in between.
You can create a self-signed certificate which will provide the necessary configuration to encrypt the connection, but will not protect you from man in the middle attacks for the same reason that unauthenticated Diffie-Hellman key exchange will not.
You can get free SSL certificates valid for 1 year from https://www.startssl.com/ - I use them for my personal sites. They're not quite as 'trusted' whatever that means, since they only do automatic checks on people who apply for one, but it's free. There are also services which cost very little (£10/year from 123-Reg in the UK).
I've implemented a different approach
Server: user name and password-hash stored in the database
Server: send a challenge with the form to request the password, store it in the session with a timestamp and the client's IP address
Client: hash the password, concat challenge|username|passwordhash, hash it again and post it to the server
Server: verify timestamp, IP, do the same concatenation/hashing and compare it
This applies to a password transmission. Using it for data means using the final hash as the encryption key for the plain text and generating a random initialization vector transmitted with the cipher text to the server.
Any comments on this?
The problem with client-side javascript security is that the attacker can modify the javascript in transit to a simple {return input;} thereby rendering your elaborate security moot. Solution: use browser-provided (ie. not transmitted) RSA. From what I know, not available yet.
How can I send sensitive data over an
insecure channel
With a pre-shared secret key. This is what you attempt in your suggested solution, but you can't send that key over the insecure channel. Someone mentioned DH, which will help you negotiate a key. But the other part of what SSL does is provide authentication, to prevent man-in-the-middle attacks so that the client knows they are negotiating a key with the person they intend to communicate with.
Chris Upchurch's advice is really the only good answer there is for 99.99% of engineers - don't do it. Let someone else do it and use their solution (like the guys who wrote the SSL client/server).
I think the ideal solution here would be to get Twitter to support OpenID and then use that.
An ssl certificate that is self-signed doesn't cost money. For a free twitter service, that is probably just fine for users.
TO OLI
In your approch for example i'm in the same subnet with same router, so i get the same ip as my collegues in my work. I open same url in browser, so server generates the timestamp with same ip, then i use tcp/ip dump to sniff the hashed or non hashed password from my collegues connection. I can sniff everything he sends. So i have all hashes from his form also you have timestamp(my) and same ip. So i send everything using post tool and hey i'm loggen in.
If you don't want to use SSL, why not try some other protocol, such as kerberos?
A basic overview is here:
http://www.kerberos.org/software/tutorial.html
Or if you want to go somewhat more in depth, see
http://www.hitmill.com/computers/kerberos.html
I have a similar issue(wanting to encrypt data in forms without paying for an ssl certificate) so I did some hunting and found this project: http://www.jcryption.org/
I haven't used it yet but it looks easy to implement and thought I'd share it here in-case anyone else is looking for something like it and finds themselves on this page like I did.