
Show HN: Onions.io – secure and open-source text storage in the cloud - bennyg
https://www.onions.io
======
tptacek
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?

~~~
bennyg
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).

I'm imagining this is a good crypto library for its Ruby implementation:
[https://github.com/cryptosphere/rbnacl](https://github.com/cryptosphere/rbnacl)

~~~
tptacek
Yes. Please drop the hand-rolled crypto you have now and use libsodium or
rbnacl.

~~~
bennyg
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.

~~~
wglb
_But I do believe I have fixed the problems you raised._

Except for the one where you are rolling your own and not using the libraries
he suggests.

~~~
bennyg
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.

------
handsomeransoms
Two concerns:

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.

------
jtheory
Don't forget the SSL config analysis -- you're not bad, but not up to the
DuckDuckGo standard yet!

[https://www.ssllabs.com/ssltest/analyze.html?d=onions.io](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.

------
jcoder
How do you prove that onions.io is running
[https://github.com/onionsapp/Onions-Rails-
API](https://github.com/onionsapp/Onions-Rails-API)?

~~~
bennyg
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.

~~~
ef4
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.

~~~
droope
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.

------
616c
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.

[0] [https://github.com/turtl](https://github.com/turtl)

[1]
[http://docs.services.mozilla.com/sync/](http://docs.services.mozilla.com/sync/)

------
kevinday
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.

~~~
bennyg
To be honest, I'm not sure yet.

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.

~~~
lmm
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.

------
gingerlime
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.

[1] [https://github.com/clipperz/password-
manager](https://github.com/clipperz/password-manager)

------
adventured
This caught my attention, but then I read this:

"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.

------
ludicast
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".

That said, there is definitely a niche for this sort of app

~~~
ketralnis
> 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.

~~~
jtheory
Also: it's still in beta and not yet open to the public, for the very reason
that the creator is still sorting out these questions.

------
ef4
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.

~~~
bennyg
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.

------
cdoxsey
The concept is flawed. You can never trust a 3rd party to not read your data;
the only option is to run your own server.

Also for passwords you don't want the data to be permanent. Something like
this would be better:
[https://github.com/badgerodon/selfdestruct](https://github.com/badgerodon/selfdestruct).

------
bennyg
Beta Codes:

    
    
      ebcc8d74-edee-46c6-a640-020741a9b2eb
      15ea4fa0-3ad6-46ea-a3b8-07136117f722
      64641c44-2d78-495d-b900-4534312f59be
      fdb92162-6de6-4868-b5f1-d5e1ba35516d
      c8d0fbb9-60c5-4156-92d2-8c9db48f1600
      e88a760e-7a4b-4ff2-9276-039d7630edd1
      59bd9776-ee53-401f-9d20-8a259a25007f
      80888b40-bce3-4d1d-a9ad-e555e5aaf37c
      5ed2e9e2-c152-4176-b7cb-aaf4700c4f4b
      2ab69676-c618-43bb-90fc-0353ceac756c
      a913abf4-5dbc-44ed-9e32-0b9ec08dd69d
      9cd734ff-e28e-42e4-95df-635f7d487dcc
      b4261b97-e6a9-4b10-a219-21f7b36913fc
      14d108b3-652b-4123-88f7-bdf8e3d87c04
      a8090aaa-b9ec-417f-9e62-98f0972587d4
      949c1467-40c1-4b93-bca8-97d80b756926
      b61fc80f-0f9e-45a9-82f3-61b0deaf52c9
      84b449d5-6b0b-4775-b4b0-531d50f25afc
      a09023fd-4ff2-4e8d-aabb-ee3c94dec08b
      806db2ef-42e3-46c6-901a-053da569561e
      4654e5c5-878a-4609-95c0-060f3ea81669
      21092de4-c521-4329-9bc7-1793dd3c1b4a
      4ea9e54c-cc31-40b4-bcf7-fadf75859964

~~~
bennyg
These codes are dead. Try these:

    
    
      64641c44-2d78-495d-b900-4534312f59be
      1659560f-e90c-4617-9a1b-d909b7fdb3ec
      2548e52a-050a-42eb-ab02-9bd4f00e431a
      4f634b69-e77a-430d-9d44-9b831a695572
      3042ae64-09aa-431f-beb2-8092c99827cd
      bb049652-e7b4-479f-ab4f-6450bf4e152e
      4c219d83-8c3b-4272-9df0-be2cae314df8
      a4c5431d-061f-415b-9b31-9b87e4f76518
      ea957849-8e8e-44f2-8dd4-50061c817fad
      0fe3d4fc-c51d-47ad-93c4-c6328e387900
      a6f64f88-93d3-490a-bc2a-ef3977e9d260
      e6b8a89e-e93b-4af6-b2a5-349deebffac4
      20b0225a-57a9-434f-a78a-72f612747c63
      9496fc4b-fb2d-4bac-8d9c-43839f715fdf
      406c5740-f8f3-4f62-ab67-c3fd20db955e
      06c47d64-bb0d-4501-b45d-f684f84fd1de
      554194d0-969c-4fe9-8aae-d8cd75225036
      b599bf82-5d44-408a-b1c7-fe4f84c7d46e
      eedea074-ca77-4d04-b575-47acbf5311ec
      329e9855-30b0-46db-bfa5-5ffe37d84a78
      a31e3833-4ea1-4296-aa3e-e285f926e9a6
      35f61f09-3326-4c0d-9ca9-672a26231140
      260fdecf-e555-48b2-be7e-c88b4ea5c50c
      d11c6b47-c333-4ae2-bf7b-6ed28b3405c0
      4443e955-9054-438c-bc80-5a56702fbc7a
      e3694c44-c370-4e89-b8f7-25bb3ea67250
      48797a6f-a5d1-40c8-bf30-2ab998413a90
      0768289b-871d-4802-aef8-0fbb2ca0bf7b
      24f20237-38c4-4be0-9d9e-8f30028796b1
      a21c9beb-6a3e-4c37-9047-331fd9c6db62

~~~
chanchal1987
All beta codes are not working.

------
yeukhon
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".

~~~
bennyg
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.

~~~
yeukhon
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.

------
mavci
I login with empty password. Just click login button.

------
al2o3cr
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.

* 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...](http://blog.phusion.nl/2013/01/04/securing-the-rails-session-secret/)

* 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.

~~~
bennyg
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.

