Project

General

Profile

Feature #14337

We need add primitives in Ruby that help us compartmentalizing specific parts of our code (with guarantees)

Added by vasilakisfil (Filippos Vasilakis) almost 2 years ago. Updated almost 2 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:84700]

Description

With the recent incidents in the npm community (https://github.com/npm/registry/issues/255), the earlier the unethical moves of Kite (https://theoutline.com/post/1953/how-a-vc-funded-company-is-undermining-the-open-source-community), the fact that a maintainer of a popular gem can publish a new version in Rubygems without publishing anything in Github, or that the maintainer can bump and publish a new version in Github but still send different code in Rubygems, from which people download the gem, it feels that we need to put some thinking on security features of Ruby. It feels like any ruby gem that I include in my Ruby app can access the db credentials and can do pretty much anything (even overriding methods) because in Ruby you can access everything even unexposed instance variables.

We need to add primitives in Ruby (although I suspect that other languages like PHP, Elixir and Javascript probably have the same issues) that help us compartmentalizing specific parts of our code.

freeze method implemented in the language itself is a good start. When you freeze a constant, you make it immutable and thus cannot be changed by any means. We need more primitives like that. We need ways to say that this class cannot be extended/reopened/altered by default. The same goes with methods, we need to give ways to developers to not allow critical methods to be altered. We need to instruct constants that are not supposed to be accessible by outside as private only by explicitly marking them as private (it needs some special work). Or be able to instruct Ruby to not expose any information regarding a class/instance, like instance variables etc. Because a lot of confidential data sit there.

Once we do that, then the application frameworks need to use those primitives but also build upon those. For instance, in Rails, critical (if not all) classes/methods/constants should not only be “frozen” (which means cannot be modified by malicious code) but also be declared as private-only so that installed gems don’t even have access to such information by default. Let the user inject what she thinks that is necessary for her installed gem to work, through the initializers. Classes should not be open for extension by default, unless the user instructs differently (that could be a bit challenging).

It might take some time and effort but we need to invest time and find better ways on how to protect ourselves from such and similar attacks.

What do you think folks, would it be something that you would consider ?

History

Updated by Hanmac (Hans Mackowiak) almost 2 years ago

i think if Ruby would freeze everyting and close it up, that would be a no go for the language itself and its death
it's a feature of ruby that you can extend each class and add more features into it

for example your favorite Rails wouldn't even work anymore for most of the stuff if it couldn't extend the core classes.
you can kiss shortcuts like this "4.days" good bye, because they where prevented by your idea

Updated by vasilakisfil (Filippos Vasilakis) almost 2 years ago

I don't agree locking up everything. What I am saying is being able to lock down specific parts (like the object that handles confidential data, like db credentials etc). Being able to hide such things.

I was informed that you can stop monkeypatching by freezing a class object, something I didn't know. Well that's something Ruby community should start push forward that as a best practice for critical parts of code to all lib/framework maintainers.

Yet, we need more than that. For instance, being able to hide instance variables which contain tokens/secrets or maybe give the ability to freeze only specific parts of a class.

In general start act for attacks like this, even if it's adding features in Ruby language or pushing the community to follow some best practices around these attacks.

Updated by dsferreira (Daniel Ferreira) almost 2 years ago

Ruby was not meant to be handled like that.
Security should be handled in different ways.
If you’re concerned about the security of your app, and you should, you should work with ruby core directly and use only ruby gems in which you can trust due to wide spread use by the community.
Otherwise you should audit the gems yourself.
These security problems always existed in ruby and you have a countless number of applications (e.g. Github) in the wild using ruby.
If you use ruby you should obey ruby philosophy.
In ruby almost everything is allowed.
“With great power comes great responsability”

Updated by dsferreira (Daniel Ferreira) almost 2 years ago

GitHub is not the place where you should audit the gems.
Right?

Updated by vasilakisfil (Filippos Vasilakis) almost 2 years ago

dsferreira (Daniel Ferreira) wrote:

Ruby was not meant to be handled like that.
Security should be handled in different ways.
If you’re concerned about the security of your app, and you should, you should work with ruby core directly and use only ruby gems in which you can trust due to wide spread use by the community.
Otherwise you should audit the gems yourself.
These security problems always existed in ruby and you have a countless number of applications (e.g. Github) in the wild using ruby.
If you use ruby you should obey ruby philosophy.
In ruby almost everything is allowed.
“With great power comes great responsability”

I don't agree with that, mostly because what I am suggesting is a backwards-compatible extension to the Ruby model what would increase security significally, on demand. Of course I check the gems I add and the gems those gems use, but that gives me no guarantees at all. What I want is guarantees. Even an advanced/expert Ruby developer could be easily tricked with the current model and there is no question to that that there is nothing you can do about it.

Updated by dsferreira (Daniel Ferreira) almost 2 years ago

Are you saying ruby cannot be used if you want to develop a secure application?

Updated by vasilakisfil (Filippos Vasilakis) almost 2 years ago

dsferreira (Daniel Ferreira) wrote:

Are you saying ruby cannot be used if you want to develop a secure application?

Do you know any way to store information in Ruby that are hidden to third-party classes ?

Updated by dsferreira (Daniel Ferreira) almost 2 years ago

Do you know any way to store information in Ruby that are hidden to third-party classes ?

That is why I said to you that the way you are thinking about the problem is not the ruby way.
Third party classes stop being third party the moment you require them in your app.

The code base of one application is a single entity with shared memory.

If you really want to enforce a third party nature of some very weird class what you should do is to decouple that piece of code into a different application with its own independent process and even independent CPU and server (spectre attack and all the others that are still only known by the “North Korean” hackers and have been out there for more than twenty years but that big IT corps state there are no known attacks registered so far...)

So for control of security communication between classes you use different APIs.

Micro services architecture, so on

Updated by dsferreira (Daniel Ferreira) almost 2 years ago

Easier solution: Develop your own class in top of ruby core or fork the third-party code and control the development and delivery cycle

Updated by normalperson (Eric Wong) almost 2 years ago

vasilakisfil@gmail.com wrote:

Of course I check the gems I add and the gems those gems use, but that gives me no guarantees at all. What I want is guarantees.

You realize a only a few days ago Spectre and Meltdown were
announced, right?

The kernel and hardware are on a completely different level than
userspace in terms being able to provide safety guarantees than
userspace. If the hardware can't even get it right; do you
honestly think Ruby or anything else in userspace has a chance
at providing the guarantees you want?

Freezing in Ruby is broken by flipping a SINGLE bit. Memory
corruption, hardware glitches or any wayward C extension that
gets loaded can do that (and of course they can do way worse).
Heck, we're even getting rid of $SAFE because it provides a
false sense of safety: https://bugs.ruby-lang.org/issues/5455

If you want data isolation, then at the very MINIMUM you need to
isolate at the *nix process and user level (create different
user accounts for everything you run) so the kernel + hardware
can do what they're supposed to do.

But, kernel bugs sometimes happen, so using VMs have a bit more
isolation and protection... Except hardware cannot be trusted,
either, so you really need to be separating things at the
physical level. Even then you need to make sure your firmware
isn't uploading stuff to the cloud behind your back.

There's real things that you should be doing like auditing all
the code you use and not having unaudited code (this includes
firmware, microcode, and drivers). But introducing this stuff
at the userspace level is an utter waste of time. Start with
using less code and simpler code so you have less to audit.

Updated by shevegen (Robert A. Heiler) almost 2 years ago

I was about to write a lot but I think it is better to be short.

I am not at all against more security; perhaps rubocop could help
for auditing code and enforcing styles.

But the suggestion above would cripple ruby's philosophy and
this is very, very, very bad. So I agree with hanmac - the suggestion
is not a good one.

Also:

the fact that a maintainer of a popular gem can publish a new version
in Rubygems without publishing anything in Github

Can you show us where rubygems.org requires a github repository?

Because as far as I know, it is not required of people who are
registered on rubygems.org, to also have a github repository.

I am also totally and completely against forcing people to have
a github account, in order to use rubygems.org and publish their
own gems.

If you feel insecure about other people writing code then do not
use unaudited code. Or write your OWN code solution.

If you want to, you could also convince the rubygems.org team
to provide additional ways to review some gems perhaps ... but
this would take additional resources and I wonder where you could
get the manpower for it. You'll never have full security without
mass-restrictions - and Intel showed that even these restrictions
are never 100%.

I also very much doubt that npm and JavaScript can be compared
to the ruby ecosystem. That is not to say that ruby should not
learn from problems in other "scripting" languages - but please
without crippling ruby's philosophy.

Updated by Hanmac (Hans Mackowiak) almost 2 years ago

also about ruby gems:

you can push the C-Lib gems as source but also as precompiled ones (for ones without compiler)
now if you don't have add an repository, or even if the code is different,
you can't trust the precompiled C-Lib gem.

i for myself does not prefer them, because the things i did are build exactly to the system it's build on

also even i use github and its feature as OAUTH service to login somewhere else, i would not like it if it's required for ruby

Updated by vasilakisfil (Filippos Vasilakis) almost 2 years ago

I never said that Github is required for Rubygems, I was referring to a common practice. Even if I audit the code in my own machine (nothing to do with Github), who can guarantee me that when the gems that are fetched on production from Rubygems, the maintainer of a misbehaved gem won't push a custom version ?

From what I understand your point is: security is very difficult to achieve even on Kernel/Linux level, so we won't add primities to Ruby that could enhance security.

I don't think I agree with that. Although I understand that security is a hard thing to achieve, enhancements wouldn't hurt, given that are backwards compatible with existing codebases and allows the developer to choose if she wants them or not. It's very different to implement a simple Ruby gem that extracts db passwords from targeted Ruby classes, and creating a C lib that exploits a Kernel vulnerability.

Updated by rosenfeld (Rodrigo Rosenfeld Rosas) almost 2 years ago

The issue described in this article talking about issues involving NPM also applies to RubyGems:

https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5

I suggest you to read that article because in any moment the author suggests changing Node.js to fix this issue. I don't actually think any Ruby implementation would be able to do anything to fix this issue. This could be discussed in the RubyGems project (or NPM, for JavaScript sources), but this can't be fixed in the language implementation domain in my opinion.

Updated by matz (Yukihiro Matsumoto) almost 2 years ago

  • Status changed from Open to Closed

If your intention of compartmentalizing is security, I don't agree that much. The reason was stated by normalperson (Eric Wong) above.

I feel some kind of compartmentalizing may work well for organizing software structure. It may be packages or modules in other languages. But it must be a different story, that should be discussed in the separated thread.

Matz.

Also available in: Atom PDF