I know you say you're not storing the password on your end, but what prevents you (or a hacker who somehow gets access to your server) to suddenly start logging the passwords as they're sent to the server when someone logs in?
You've got what looks like a good approach to storing things in an encrypted way, but it's still requiring the user to trust that the server is actually doing what it says it's doing and no more.
- How to make sure the entire process is more transparent, beyond hosting the code on Github right now. Basically, how do I prove that that is the version that's in production in a simple manner without compromising the server as well?
- Is there any way to make sure that passwords and usernames aren't logged in between the security layers so even if I were to upload malicious code (I won't), that I'm out of the equation and people can still verify this?
Right now, this is just my MVP, and I'm releasing beta codes to make sure the server doesn't crash and that I don't get charged through the roof by Heroku before I have enough moolah to support this side project. I was hoping for a little community input on ways to verify these things. Thanks for the criticism man, it's definitely warranted.
I think the only way would be to make a browser extension available for those who care enough to use. Fundamentally, anything on a web page belongs to the server that sent that web page, and if that server is compromised so is the browser window.
maybe I can help with hosting your mvp in germany. No NSL is accepted here and I have one or two ideas how to show the server side's integrity status. PM me reddit:3f3nd1
Right now I'm not sure yet. This is just my MVP, and I haven't quite figured that out yet. My first thought was a SHA hash of the Server vs. the same hash of the Github code. Unfortunately I'm not quite sure if that's feasible or realistic based on how things are set up.
Any thoughts on a good method for this? It's definitely something I want done.
That's trying to solve the wrong problem. Rather than try to prove the server is trustworthy (which is impossible), make the server untrusted.
Which means finding a way to securely, reliably do the encryption on the client. Which would be a useful thing to build, since all the current ways of doing that have problems.
Don't take these suggestions the wrong way: even though the security won't be perfect for a while (or ever), these projects, which make encryption available to the mainstream are priceless.
Crypto.cat uses a browser extension, I think (disregarding all of cryptocat's woes) that is the way to go.
You appear to be encrypting "Onions" with CBC with a static IV, using the hash of a string as the key, and with no integrity. You can't use a static IV. You can't encrypt without providing for authenticity. How do you know you don't have a padding oracle? The code you have right now will, from what I can tell, behave differently if an attacker modifies the ciphertext.
Where did the crypto design for this system come from?
Why are you hand-rolling your own crypto? Why didn't you use something like Nacl instead, which was already carefully designed to make crypto safe for developers that haven't studied the topic?
This is why it's in Beta. Thanks for pointing that out to me - I'm gonna' roll that in right now (although everyone will lose their data as it stands, this is good).
Getting lib sodium and rbnacl to play nice with Heroku has proven to be outright impossible as of now. But I do believe I have fixed the problems you raised.
- The key is not a string, it's generated using PBKDF2_HMAC_SHA1 for 20,000 rounds, and then passed in to the cipher function - where it's SHA256'd. The reason for this is I do plan on having other clients beyond the website (iOS - which is practically finished, Android, etc) where just in case their generated Key happens to be injection-ready code, I'm manipulating it one last time before going in and encrypting/decrypting.
- I'm authenticating the messages based on a server config variable that is an authentication tag like so: SHA256(SERVER_AUTH_TAG + encrypted_data). The openssl version I'm using doesn't have self-built authentication in its AES cipher suites. Is this a good/bad avenue to go down for message authentication? I feel like if someone takes my server and gets the SERVER_AUTH_TAG then there's bigger problems anyways.
- I'm now randomly generating initialization vectors for each piece of encrypted data. So, for an Onion where there's a title and info, the title gets its own IV, and so does the info. When you edit the title, it gets a whole new IV as well.
The thing is, I'm not rolling my own here (minus message authentication, but based on cursory reading, this is how it's done anyways). I'm using standard OpenSSL libraries - things that are vetted, and I'm using like they suggest. Rolling my own was using it without an IV and without message authentication (aka getting it half right). I'm not doing that any more.
Obviously the libraries he suggested are different than the ones I'm using, but that in itself shouldn't be a case for dismissal. The ones I'm using are industry standard. His suggestion uses a different stream cipher and a different key generation scheme, the ciphers and key generation scheme I'm using are what are behind SSL/TLS - something which is not broken. The NSA didn't break this, they bought their way through the crypto, which should tell you something about its strength.
I am generally curious though, to make sure I got what I did right. I think I have - and again the only part I'm not sure about entirely is message authentication. Some places online suggest including the IV in with the authentication. However, since the code is open to the public, and if an attacker were to take my database, they'd have the IV no problem. The only thing they wouldn't have is what I'm signing each message with, the thing that really does the authentication, my server config variable only used for message auth.
I am not trying to be mean, but justify that as "that's why it's in beta" is a wrong idea to sell your project/product. I mean your whole point of this project is security so make it right in the beginning.
1. Your security model is identical to that of Lavabit, and is equally vulnerable to you being legally compelled (and kept quiet with a gag order) to collect your user's passwords. What is your threat model?
2. On your "About" page, you explicitly state that your project has nothing to do with Onion routing. Then why name it onions.io? The domain name is similar to onion.to, a popular tor2web proxy. The logo is extremely similar to that of the Tor Project. This all seems like false advertising given that the project has nothing to do with those well-known concepts and projects. I would seriously considering changing the name and logo.
> I'm not being a hater, but tbere is a lot of "I'm not sure" in your answers. Not the sort of thing that is reassuring to see from somebody claiming a solution is "secure".
I'd rather hear "I'm not sure" than "Don't you worry about X, let me worry about X!" or just making something up, or speaking inaccurately off the cuff.
I'd rather hear "I'm not sure" than hear that someone is sure, but wrong.
The README throws up huge red flags to anyone who has studied crypto.
For example, saying you use AES-256 without explaining what cipher mode really doesn't say anything at all about the security of your system.
And even if your crypto system is awesome, it doesn't matter at all because it's all running on the server, where the NSA (or local equivalent) can simply force you to turn it off at any time.
If you really care about bringing strong privacy to users, you need to give them something they can run locally, so they don't need to trust your server.
I fixed the README to say it was using CBC for the cipher mode, thanks for that input. (though this will be changing to NaCL's implementation of XSalsa20 very, very soon)
I made it open source so people can also fork and run on a local machine, that only they hit - but I plan on launching an iOS app very soon for it as well, so you can do something on one computer, and then use another to make changes or see things on the go. This is the only reason I made it in the cloud.
Generally agreed with other comments -- it's impossible to prove that the server is trustworthy (just imagine how easy it would be to tweak the server code to simply log all the cleartext that comes in...), so a purist approach forces you to encrypt on the client-side. On the other hand, a good & open server architecture, hosted somewhere the gov't can't oblige you to cheat, with external security audits goes a long way as well. Good usability and reliability often involve some security trade-off (think about password resets -- these are next to impossible if the server is untrusted!); the important thing is to figure out the best balance based on your intended customers.
Thinking more about the purist solution -- if the server is untrusted in your solution, you don't even need to provide the server anymore; let someone bigger handle that for you. I.e., you could generate a secure data file with your OSS client software (like KeePass or similar do), and let Dropbox or whoever else store it safely for you.
If you could make this really useable (incidentally, KeePass is not a good model here), that'd be a valuable creation. Unfortunately, then you're stuck building native applications for multiple platforms, which is probably not what you were hoping to be working on.
A guy recently posted something similar written in Common Lisp called Turtl. [0] You might want to check that out as it avoids some of your design problems, namely "authentication" is really just entering the decryption key in your browser. All data is decrypted on the browser, and the host-proof service on the service knows none the wiser.
Also see Firefox Sync. [1] But I am seem to be one of five people who advocate it.
Interesting idea. Some notes / comments / questions on the posted code (in no particular order):
* setting up a separate routing namespace for the API would clean up a number of things. In particular, it would make the web-only actions much clearer; calling respond_with with a JSON error payload and then relying on it to render the template (as done in OnionsController#index, for instance) is terribly confusing on a first read.
* does logging in actually set session[:UserKey]? It doesn't appear to, but that would make returning users unable to decrypt their existing onions.
* The encryption code in OnionsController would be better suited in the Onion model, especially since the decryption code is already there.
* the API for adding onions (OnionsController#addOnion) does not encrypt the data before storing it. Is this intentional?
* every action that modifies onions creates a new session. From the way that new_session works, I'm guessing this is to provide "session expiration" that's reset every time a user changes something. Would updating the timestamp on the user's existing Session accomplish the same thing, or have I missed something?
Some more code-review oriented notes:
* Some of your class methods in the models would be clearer as instance methods - for instance, both account_exists and pass_is_good take the hashed username as an argument and find the corresponding Account object. pass_is_good could be an instance method on Account. As another example, the code inside the loop in decrypted_onions_with_key could be an Onion instance method (telling an Onion object to decrypt itself vs. doing it externally).
* the comment character in Ruby is #, not surrounding things in / symbols (which creates a Regexp literal). In most cases (config/routes.rb, for instance) this happens to not cause problems - but it's still not a good habit to get into.
* some style notes: none of these affect the operation of your program, but they will affect how efficiently other developers read your code and work with it.
First, pick a tab setting in your editor of choice and stick with it. The "Ruby standard" is 2 spaces, but if you prefer something else at least be consistent.
Second, check out some of the Ruby style guides regarding naming. CapitalizedCamelCase is makes for somewhat odd-looking database column names.
Thanks for all the input, Ruby is basically the equivalent of ESL to me. I'm an Objective-C programmer by nature (self-taught at that, I have a Bachelor's in Graphic Design as it stands). These are all really good points, as I get better in this language.
Logging in does generate and set the UserKey. I'm making a rolling, resetting SessionKey, so as not to keep one session alive forever. Every action makes a new one (also hence the primary key resetting that happens when it approaches the limit of a 32bit signed int).
Also, regarding tabs, I just can't get a damn editor to actually do these correctly. I've been using Sublime and then switched to RubyMine recently, but both are awfully annoying. Clicking in a new line doesn't automatically start the cursor at where the next tab should be, it starts it exactly in the line where I clicked - making me have to hit return again to get a new line in the appropriate place. Sometimes I just go on because I'm trying to put the idea down, resulting in shitty looking code. The only IDE I've seen that does this right is Xcode, and I really wish RubyMine could do it, because it's also been very nice so far. But poor UI in IDEs is neither here nor there for this project. Thanks again for the input.
"Things like passwords, debit card information or social security numbers lend themselves perfectly for Onions."
You can't be serious about that. Even if you could perfectly safely store SS numbers, don't even dare try to convince the public of that, they're going to think you're full of it instantly and the trust you require will be gone (deserved or not). You have to remember to account for the irrationality of people when you design a service, things they're scared of (even if they shouldn't be, and so on).
I'd argue that in general people don't feel great giving their SS number to the most secure companies on earth. Giving it to Onions.io? Forget about it. Don't go there unless you have the extraordinary reputation to overcome the fear people have about storing such sensitive info online.
i suggest you spend time looking at Persona so that users can just login with a Persona account without you warning them "well you have to remember a password".
I would, but the whole purpose of this is to not tie any information back to a person, aka keep it anonymous. Persona accounts use email, so there's no point in using them.
Well, if you think people are going to create another username and another password to hide identity, that assumption is bad as well. You can launch a study and you will find even a lot of the "hackers" here will get lazy at creating a new password and a new username. You probably feel the same anyway.
There is a whole bag of reasons why we don't want to reinvent an auth system anymore other than recording the username and give a user privilege/level to that name in the database.
and with server logging, you have to do a lot of work to ensure your server isn;t logging ip addresses which effectively makes certain types of debugging and defense very difficult (intrusion detection for example).
You also have to be aware of ISP logging as well. In the end, no, you can't guarnatee no one can know the identity.That philosphy is flaw.
You goal is to ensure auth is as minimal as possible, and maximize security of information retrieval and storage.
if you want to reduce the abiilty to know the user idetntify without a raintable / bruteforce, hash the identity. hash the username / email address.
That's the only way to hide it from an obvious search.
I think it's great that people are trying to tackle this, and I feel a little sorry for the creator for some of the rather-harsh criticism. That said, given the nature and aim of the project, it really needs to live to very high standards to deliver on its promise. And some of those harsh-sounding words are to a large extent helpful. Putting things into perspective and helping identify the weak spots.
To me this looks similar (at least on the surface) to clipperz[1], even though I believe clipperz does all crypto on the client-side. Of course, both suffer from similar attack vectors or trust issues either way. Client-side does not mean you don't have to trust the server.
I hope for the sake of the project, that it gets more than just passing comments (however helpful), but rather serious engagement from people with experience in this field.
37 comments
[ 2.6 ms ] story [ 83.7 ms ] threadYou've got what looks like a good approach to storing things in an encrypted way, but it's still requiring the user to trust that the server is actually doing what it says it's doing and no more.
There are a couple things to figure out:
- How to make sure the entire process is more transparent, beyond hosting the code on Github right now. Basically, how do I prove that that is the version that's in production in a simple manner without compromising the server as well?
- Is there any way to make sure that passwords and usernames aren't logged in between the security layers so even if I were to upload malicious code (I won't), that I'm out of the equation and people can still verify this?
Right now, this is just my MVP, and I'm releasing beta codes to make sure the server doesn't crash and that I don't get charged through the roof by Heroku before I have enough moolah to support this side project. I was hoping for a little community input on ways to verify these things. Thanks for the criticism man, it's definitely warranted.
Any thoughts on a good method for this? It's definitely something I want done.
Which means finding a way to securely, reliably do the encryption on the client. Which would be a useful thing to build, since all the current ways of doing that have problems.
Crypto.cat uses a browser extension, I think (disregarding all of cryptocat's woes) that is the way to go.
Where did the crypto design for this system come from?
Why are you hand-rolling your own crypto? Why didn't you use something like Nacl instead, which was already carefully designed to make crypto safe for developers that haven't studied the topic?
I'm imagining this is a good crypto library for its Ruby implementation: https://github.com/cryptosphere/rbnacl
- The key is not a string, it's generated using PBKDF2_HMAC_SHA1 for 20,000 rounds, and then passed in to the cipher function - where it's SHA256'd. The reason for this is I do plan on having other clients beyond the website (iOS - which is practically finished, Android, etc) where just in case their generated Key happens to be injection-ready code, I'm manipulating it one last time before going in and encrypting/decrypting.
- I'm authenticating the messages based on a server config variable that is an authentication tag like so: SHA256(SERVER_AUTH_TAG + encrypted_data). The openssl version I'm using doesn't have self-built authentication in its AES cipher suites. Is this a good/bad avenue to go down for message authentication? I feel like if someone takes my server and gets the SERVER_AUTH_TAG then there's bigger problems anyways.
- I'm now randomly generating initialization vectors for each piece of encrypted data. So, for an Onion where there's a title and info, the title gets its own IV, and so does the info. When you edit the title, it gets a whole new IV as well.
Except for the one where you are rolling your own and not using the libraries he suggests.
Obviously the libraries he suggested are different than the ones I'm using, but that in itself shouldn't be a case for dismissal. The ones I'm using are industry standard. His suggestion uses a different stream cipher and a different key generation scheme, the ciphers and key generation scheme I'm using are what are behind SSL/TLS - something which is not broken. The NSA didn't break this, they bought their way through the crypto, which should tell you something about its strength.
I am generally curious though, to make sure I got what I did right. I think I have - and again the only part I'm not sure about entirely is message authentication. Some places online suggest including the IV in with the authentication. However, since the code is open to the public, and if an attacker were to take my database, they'd have the IV no problem. The only thing they wouldn't have is what I'm signing each message with, the thing that really does the authentication, my server config variable only used for message auth.
1. Your security model is identical to that of Lavabit, and is equally vulnerable to you being legally compelled (and kept quiet with a gag order) to collect your user's passwords. What is your threat model?
2. On your "About" page, you explicitly state that your project has nothing to do with Onion routing. Then why name it onions.io? The domain name is similar to onion.to, a popular tor2web proxy. The logo is extremely similar to that of the Tor Project. This all seems like false advertising given that the project has nothing to do with those well-known concepts and projects. I would seriously considering changing the name and logo.
Not the sort of thing that is reassuring to see from somebody claiming a solution is "secure".
That said, there is definitely a niche for this sort of app
I'd rather hear "I'm not sure" than "Don't you worry about X, let me worry about X!" or just making something up, or speaking inaccurately off the cuff.
I'd rather hear "I'm not sure" than hear that someone is sure, but wrong.
For example, saying you use AES-256 without explaining what cipher mode really doesn't say anything at all about the security of your system.
And even if your crypto system is awesome, it doesn't matter at all because it's all running on the server, where the NSA (or local equivalent) can simply force you to turn it off at any time.
If you really care about bringing strong privacy to users, you need to give them something they can run locally, so they don't need to trust your server.
I made it open source so people can also fork and run on a local machine, that only they hit - but I plan on launching an iOS app very soon for it as well, so you can do something on one computer, and then use another to make changes or see things on the go. This is the only reason I made it in the cloud.
https://www.ssllabs.com/ssltest/analyze.html?d=onions.io
Generally agreed with other comments -- it's impossible to prove that the server is trustworthy (just imagine how easy it would be to tweak the server code to simply log all the cleartext that comes in...), so a purist approach forces you to encrypt on the client-side. On the other hand, a good & open server architecture, hosted somewhere the gov't can't oblige you to cheat, with external security audits goes a long way as well. Good usability and reliability often involve some security trade-off (think about password resets -- these are next to impossible if the server is untrusted!); the important thing is to figure out the best balance based on your intended customers.
Thinking more about the purist solution -- if the server is untrusted in your solution, you don't even need to provide the server anymore; let someone bigger handle that for you. I.e., you could generate a secure data file with your OSS client software (like KeePass or similar do), and let Dropbox or whoever else store it safely for you.
If you could make this really useable (incidentally, KeePass is not a good model here), that'd be a valuable creation. Unfortunately, then you're stuck building native applications for multiple platforms, which is probably not what you were hoping to be working on.
Also see Firefox Sync. [1] But I am seem to be one of five people who advocate it.
[0] https://github.com/turtl
[1] http://docs.services.mozilla.com/sync/
* setting up a separate routing namespace for the API would clean up a number of things. In particular, it would make the web-only actions much clearer; calling respond_with with a JSON error payload and then relying on it to render the template (as done in OnionsController#index, for instance) is terribly confusing on a first read.
* does logging in actually set session[:UserKey]? It doesn't appear to, but that would make returning users unable to decrypt their existing onions.
* I really, really hope that isn't your actual session secret in config/initializers/secret_token.rb. More info on why this is bad and how to fix it here: http://blog.phusion.nl/2013/01/04/securing-the-rails-session...
* The encryption code in OnionsController would be better suited in the Onion model, especially since the decryption code is already there.
* the API for adding onions (OnionsController#addOnion) does not encrypt the data before storing it. Is this intentional?
* every action that modifies onions creates a new session. From the way that new_session works, I'm guessing this is to provide "session expiration" that's reset every time a user changes something. Would updating the timestamp on the user's existing Session accomplish the same thing, or have I missed something?
Some more code-review oriented notes:
* Some of your class methods in the models would be clearer as instance methods - for instance, both account_exists and pass_is_good take the hashed username as an argument and find the corresponding Account object. pass_is_good could be an instance method on Account. As another example, the code inside the loop in decrypted_onions_with_key could be an Onion instance method (telling an Onion object to decrypt itself vs. doing it externally).
* the comment character in Ruby is #, not surrounding things in / symbols (which creates a Regexp literal). In most cases (config/routes.rb, for instance) this happens to not cause problems - but it's still not a good habit to get into.
* some style notes: none of these affect the operation of your program, but they will affect how efficiently other developers read your code and work with it.
First, pick a tab setting in your editor of choice and stick with it. The "Ruby standard" is 2 spaces, but if you prefer something else at least be consistent.
Second, check out some of the Ruby style guides regarding naming. CapitalizedCamelCase is makes for somewhat odd-looking database column names.
Logging in does generate and set the UserKey. I'm making a rolling, resetting SessionKey, so as not to keep one session alive forever. Every action makes a new one (also hence the primary key resetting that happens when it approaches the limit of a 32bit signed int).
Also, regarding tabs, I just can't get a damn editor to actually do these correctly. I've been using Sublime and then switched to RubyMine recently, but both are awfully annoying. Clicking in a new line doesn't automatically start the cursor at where the next tab should be, it starts it exactly in the line where I clicked - making me have to hit return again to get a new line in the appropriate place. Sometimes I just go on because I'm trying to put the idea down, resulting in shitty looking code. The only IDE I've seen that does this right is Xcode, and I really wish RubyMine could do it, because it's also been very nice so far. But poor UI in IDEs is neither here nor there for this project. Thanks again for the input.
"Things like passwords, debit card information or social security numbers lend themselves perfectly for Onions."
You can't be serious about that. Even if you could perfectly safely store SS numbers, don't even dare try to convince the public of that, they're going to think you're full of it instantly and the trust you require will be gone (deserved or not). You have to remember to account for the irrationality of people when you design a service, things they're scared of (even if they shouldn't be, and so on).
I'd argue that in general people don't feel great giving their SS number to the most secure companies on earth. Giving it to Onions.io? Forget about it. Don't go there unless you have the extraordinary reputation to overcome the fear people have about storing such sensitive info online.
Also for passwords you don't want the data to be permanent. Something like this would be better: https://github.com/badgerodon/selfdestruct.
There is a whole bag of reasons why we don't want to reinvent an auth system anymore other than recording the username and give a user privilege/level to that name in the database.
and with server logging, you have to do a lot of work to ensure your server isn;t logging ip addresses which effectively makes certain types of debugging and defense very difficult (intrusion detection for example).
You also have to be aware of ISP logging as well. In the end, no, you can't guarnatee no one can know the identity.That philosphy is flaw.
You goal is to ensure auth is as minimal as possible, and maximize security of information retrieval and storage.
if you want to reduce the abiilty to know the user idetntify without a raintable / bruteforce, hash the identity. hash the username / email address.
That's the only way to hide it from an obvious search.
To me this looks similar (at least on the surface) to clipperz[1], even though I believe clipperz does all crypto on the client-side. Of course, both suffer from similar attack vectors or trust issues either way. Client-side does not mean you don't have to trust the server.
I hope for the sake of the project, that it gets more than just passing comments (however helpful), but rather serious engagement from people with experience in this field.
[1] https://github.com/clipperz/password-manager