Protecting data in extension code

Hi,

Suppose you have an array of data in your code that you want to try and protect from someone extracting. I can see that something like this doesn’t work well…

#Easy to get data from
module Org
module Ext
    #The data
    @arr = [1,2,3,4,5,"etc"]
    #Gets a specific data item
    def self.getDataItem()
        i = 3
        val = @arr[i]
        puts val
    end
    getDataItem()
end
end

Because it is easy to do this…

#Someone could do this (e.g. in the Ruby Console)...
module Org
module Ext
    puts @arr
end
end

I’ve thought of this, but wonder how secure it is and if there is a better way to protect data. Please note, I want the data to be in the code (not, for example, requested over the internet).

#An idea: Data in a local array and password needed.
module Org
module Ext
    #Stores the data
    def self.data(pw,i)
        #return if wrong pw sent.
        return if pw != "pass"
        #The data
        arr = [1,2,3,4,5,"etc"]
        return arr[i]
    end
    #Gets for a specific data item
    def self.getDataItem()
        i = 3
        val = data("pass",i)
        puts val
    end
    getDataItem()
end
end

Data in Ruby is not secure. Ruby is an interpreted language with full introspection.

Take a look at the TracePoint class. A tracepoint object could see your code call the data() method with what parameters are passed.

1 Like

Thanks Dan.

So, what is a reasonable approach for using data you want to protect in SU extensions? Where to store it and how to access it?

No file is secure nowadays with so many tools at hand to break and extract code in different languages there is no secure software, the important thing is the value of the plugin where it will make people use it and pay for it because it really is valuable.

Well, …

(a) Use the rbe encryption to obfuscate the code file(s) that deals with the data. Note that this only “hides” code whilst in file format. The code and it’s data objects become unencrypted when evaluated into Ruby.

(b) Consider some data encryption to reduce the likelihood of binary file viewers or debuggers “seeing” unencrypted data.
IMO, passing a password parameter around via method calls is likely a very weak point.

(c) Perhaps store the data in a compiled C library (or submodule) of your Ruby extension. Again, the data could be encrypted even though it is within compiled code. There are many available C encryption libraries out there. But beware that many of the old schemes have already been broken.

@Sufwave (Mattiew) is correct in that if the data is really that valuable, then someone out there will eventually hack it.

So, ask yourself is the rigmarole really worth it?

2 Likes

OK, thanks for the suggestions Dan. I appreciate it.

The RBE encryption side seems reasonable and straightforward. The issue remains when it is running in SU - access to the variables/parameters/data etc. from other extensions or the console.

Shame there isn’t a simpler solution, like a setting that can be applied in an extension to prevent access to all/some of its variables etc. from outside the extension module. Probably showing my ignorance there.

To a degree, this is re-emphasizing what @DanRathbun already said. But it is worth making a distinction between casual snoopers and full-fledged hackers. The former may look around and exploit anything they see out in the open. The latter will apply a combination of tools they get from the internet and ones of their own creation, and will patiently chip away until they penetrate any within-software technique you use.

So, again as already said, it comes down to whether your data is really so valuable that someone stealing it is a truly major issue. And if it is, perhaps the whole idea of putting it into a SketchUp extension is unwise.

1 Like

Ultimately, for the tool I have in mind, it would probably be possible to get the data one record at a time (there are a few hundred) by systematically changing the settings in the user interface - laborious but doable. So I’m after something that would probably make getting the data least as time consuming to do as doing that. Something that you could say is a reasonable measure. I accept there is no 100% measure.

What about making the method containing the data a private or protected one?

Alas, in Ruby everything is mutable and subsequent code can overrule the private and protected keywords. Besides, these only control what objects in the current app can invoke those methods on other objects.

Ruby is a dynamic language. It has metaprogramming features. One of these is the ability to execute code within a module, a class or an instance object.

So, image that you declared your data() method private with:

private_class_method :data

And somehow I’ve figured out what the password is, I do this at the console ,

Org::Ext.module_eval {
  i = 0
  in_range = true
  while in_range
    result = data("pass", i)
    in_range = false if result.nil?
    puts result
    i += 1
  end
}

… the data is printed to $stdout.

Another thought: from whom are you seeking to protect the data? Are you concerned that an unauthorized person may get physical possession of the computer and enough time to break in? Unless you program it that way, an extension and its data are not exposed outside the Ruby interpreter running inside SketchUp on your computer.

The scenario could be a user of the extension using the console in SU to access the data in the array that is in extension module. Or, instead of using the console, creating a separate extension to do the same.

You could try undefining all the introspection methods for your module which might slow down the snoopers.

Here is an example. It would be the last file loaded of those that define your module:

undefine_introspection_in_a_module.rb (3.6 KB)

The file could also use remove_method rather than undef_method.

as i mentioned don’t waste time protecting, the ideal is to generate something that proves that it is worth paying for the service or software, currently idapro and ghidra can break files with superior protections.

Thanks, I’ll take a look at that.

Now … just to reemphasize how dynamic a language that Ruby is, … a smart Rubyist can write a file that loads before yours and redefines the freeze, remove_method and undef_method methods so that they don’t do anything. And viola, they have introspection back.

It is just that interpretive scripting languages are not meant to be secure.

1 Like

Thanks Dan.

Just wondering if it is possible to either check if freeze, remove_method, undef_method etc. have been redefined (and, if so, refuse to load the extension), or to reinstate the original methods just before running the code you sent above, so it works?

You can think of this security a little like the lock on your door. The lock helps from casual thieves but if someone really wants to enter they can break through it. If you want to stop that too you can have a stronger door but if someone really really wants to get in they can cut a hole through your wall.

Using local variables give some protection over using instance variables. Using compiled code offers even more protection. If you really really want to protect against IP theft its best to have the code run on your server, not on a client machine, but it has other limitations like your tool needing a stable internet connection as well latency issues, and still isn’t guaranteed to not be hacked. It’s all about finding the balance that works for you.

There are also alternative business models where the code is open and fee but you charge for support or charge for adding the features people request, meaning you monetize your ongoing work, not the intellectual property.

Just some thoughts.

1 Like

Yes.

module Dan; end
#=> nil

Dan.method(:freeze).owner
#=> Module

Dan.method(:freeze).source_location
#=> nil (means this is defined in the native C core)

So, imagine that Module#freeze is overridden thus:

class Module; def freeze; puts "doing nada"; end; end
#=> :freeze

Dan.method(:freeze).source_location
#=> ["(eval)", 1]
# Returns an array with: [filename, lineno],
# therefore, overrides will not be nil

# The method owner is still the Module class:
Dan.method(:freeze).owner
#=> Module

Dan.freeze
#=> doing nada

However we can still get a reference to the previously defined method in Ruby 2.2+ (i.e., SketchUp 2017+):

Dan.method(:freeze).super_method
#=> #<Method: Kernel#freeze()>

# Let's freeze module Dan:
Dan.method(:freeze).super_method.call

# We now try a modification of module Dan:
module Dan; def foo; puts "bar"; end; end
#=> #<FrozenError: can't modify frozen module: Dan>

So, putting together a method override checker:

def method_overridden?(object, meth)
   object.method(meth.to_sym).source_location ? true : false
end

One caveat may be that a C extension that overrides a Ruby method might also return nil for #source_location.

2 Likes

Perhaps you are starting in the wrong place ?
this doesn’t expose the ‘data’ array.

module Org
  module Ext
    #Gets a specific data item
    def self.setDataItem(ar = nil)
       arr = ar
       arr = [1,2,3,4,5,"etc"] unless arr # always set array here !
       self.getDataItem(arr)
       return nil
     end
     def self.getDataItem(arr)
        i = 3
        val = arr[i]
        puts val
        # then do some stuff... arr is available...
    end
    setDataItem()
    # this always sets arr in any method.
  end
end

If you need to reference that array in other methods pass it on as before…
Avoiding @xx variables sidesteps the issue.
Local variables can be passed between methods inside ()