Best practise for RESTful API identifiers - identifier

So far I see these options (pseudo code):
A. Quite simple MD5 hash:
$identifier = MD5(object.id + created_at + app_secret)
=> 4c0dc8d3fdffacb65d04911291aac4cf
B. UUID:
$identifier = uuid()
=> fbcf6520-ab93-11e8-86b4-080027b55b5e
But which UUID version makes most sense? I tend to v4.
C. I'd like to have a prefix for those IDs, so I immediately know what kind of object is meant e.g. in the logs or support request.
$identifier = 'trx_' + uuid()
=> trx_fbcf6520-ab93-11e8-86b4-080027b55b5e
But is this a nice style? I could store without prefix but expose with prefix and allow requests with or without it.
What's your best praktise?

It shouldn't really matter. If I used UUID-like identifiers, I do think I would slightly prefer the UUID format because it signals to a user of an API 'This is a UUID'.
It's possible that there's some small benefits for a user, because if I see a UUID, I know I can store it in a database as a 128 bit integer instead of a string.
One thing to look out for though is security. Your first example uses the word secret which might tell me that these id's should not be guessable. UUID's are guessable and not cryptographically secure.
That being said, MD5 is insecure too so in that case both your examples are bad.

Related

Ruby/Rails: How to get same encrypted value every time we encrypt a particular string

Does ActiveSupport::MessageEncryptor support deterministic encryption so that we get the same encrypted value every time we encrypt a particular string? If not, are there any other Ruby libs that support deterministic encryption?
My goal is to get same encrypted value every time I encrypt a string and I should be able to decrypt it to original value as well.
Thanks.
You get different crypts because ActiveSupport::MessageEncryptor uses OpenSSL for encryption which requires an iv by default to prevent attackers from inferring relationships between segments of the encrypted message. I would highly recommend you to not mess around with that because you open ways for attackers to infer the encryption key.
However if you still want to do that take a look into the OpenSSL documentation of ruby. There should be a way to encrypt without vector.
Because it's a high security risk I don't add code to the answer to protect others from unnecessary loop holes.
I did not get why ActiveSupport:MessageEncryptor didn't work.
Here is another way to do it.
require 'bcrypt'
encrypted_password = BCrypt::Engine.hash_secret('password#!2#4', 'ADD SALT HERE')
you can also use it like this:
class User
SALT = 'GENERATE A STATIC SALT HERE AND KEEP IT SECURE'.freeze
include BCrypt
def password=(given_password)
#encrypted_password = Engine.hash_secret(given_password, SALT)
end
end
For the full documentation please check their repo
PS: using a static salt for all users for authentication is a bad idea.
Of course: one just need to use the same key to get the same encryption
x = ActiveSupport::MessageEncryptor.new('12345678901234567890123456789012').encrypt_and_sign('foo')
=> "bXJmRUczdjVXRFdLTitUcmkvRnk1UT09LS0vb2ZYdDRybGdWbmNXMUI1VDNnQzVBPT0=--13232bbe31d966f7d1df3aaa6fcc1cdc9eea60a1"
ActiveSupport::MessageEncryptor.new('12345678901234567890123456789012').decrypt_and_verify(x)
=> "foo"
It's hard to tell why you get different results since you didn't post any code...

Is ActiveRecord's “order” method passed with hash vulnerable to SQL injection?

Adding to the same question from (HERE), I am planning to use hash instead of string as parameter. Say,
User.order(params[:column].to_sym => params[:direction].to_sym)
Where params[:column] and params[:direction] are passed from the page for sorting the table (Reference). I even added .to_sym to both parameters just so that it will be forced into a symbol instead of string just to be safe (although I am not sure if this is even necessary)
Now, I would just like to know if this approach is safe.
P.S. tried ransack gem, however I couldn't do nested queries. So I wrote my own customizable one.
I think this is at least still open for a Denail of Service attack.
http://brakemanscanner.org/docs/warning_types/denial_of_service/index.html
The reference is from a nice gem called brakeman which finds vunerable things in a rails application.
In general I would advise you to use #dmcnally's approach from the other issue you posted.
Here an example of what I did in my own projects:
SORT = { newest: { created_at: :desc },
cheapest: { price: :asc },
most_expensive: { price: :desc }
}.stringify_keys
And then use SORT[param[:sort]] to get the sort order. You can also do this by using two seperate hashes for direction and column like you supposed. If you use brakeman you will be able to have a little but of safety since it finds most things like that.
Symbols don't protect you from SQL injection, query parametrization protects you from SQL injection - and this only on the value side, not on the column name side. The thing to take from the other article is "not safe to use interpolated strings in column name when calling .order", not "not safe to use strings when calling .order",
your example defines ordering using a hash - that hash gets translated into a parametrized SQL query in AR, so it is safe as long as you sanitize the column name. One liberal way to do this is to:
raise "Unknown column name #{params[:column]}" unless YourModel.column_names.include?(params[:column])
PS What .to_sym does in your example is that it enables a third party to define a new symbol on the ruby vm. Symbols are never garbage collected so the attacker can send many different values so that your ruby processes hog the system memory - thus opening you to a ddos attack. The cast in the end does nothing because if you look here you'll notice your value gets cast into string anyway :)

Ruby: file encryption/decryption with private/public keys

I am searching for an algorithm for file encryption/decryption which satisfies the following requirements:
Algorithm must be reliable
Algorithm should be fast for rather big files
Private key can be generated by some parameter (for example, password)
Generated private key must be compatible with public key (public key is generated only once and stored in database)
Is there any Ruby implementation of suggested algorithms?
Note Well: As emboss mentions in the comments, this answer is a poor fit for an actual system. Firstly, file encryption should not be carried out using this method (The lib provides AES, for example.). Secondly, this answer does not address any of the wider issues that will also affect how you engineer your solution.
The original source also goes into more details.
Ruby can use openssl to do this:
#!/usr/bin/env ruby
# ENCRYPT
require 'openssl'
require 'base64'
public_key_file = 'public.pem';
string = 'Hello World!';
public_key = OpenSSL::PKey::RSA.new(File.read(public_key_file))
encrypted_string = Base64.encode64(public_key.public_encrypt(string))
And decrypt:
#!/usr/bin/env ruby
# DECRYPT
require 'openssl'
require 'base64'
private_key_file = 'private.pem';
password = 'boost facile'
encrypted_string = %Q{
...
}
private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file),password)
string = private_key.private_decrypt(Base64.decode64(encrypted_string))
from here
I'm afraid you are mixing two concepts here, authentication/authorization and confidentiality, trying to cover both aspects in one single step, and that won't work. You should never encrypt "real data" with asymmetric algorithms. a) they are way too slow for that, b) there are subtle issues that, if not done right, will severely weaken the security of your solution.
A good rule of thumb is that the only thing you should end up encrypting with private asymmetric keys is symmetric keys used by a much faster symmetric algorithm. But in almost all cases you shouldn't even be doing that, because in 90% of the cases what you actually want is TLS (SSL) in those cases - I tried to explain why here a while ago.
In your case, I assume the requirements are:
confidentiality of the data that is to be stored in the database: the general public shouldn't be able to read it (or even access it)
a selected few (probably just one person) should be able to access and read that data
The first goal is generally achieved by using symmetric encryption. The second goal is, albeit related, realized by quite different means. You want the user accessing the file to be authenticated (i.e. establish the identity) and on top of that you also want them to be authorized (i.e. check whether the established identity has the right to do what they intend to). This is where asymmetric cryptography may enter the stage, but not necessarily. Since your question is tagged with Rails I assume we are talking about a Rails application. You typically already have some means to authenticate and authorize users there (most likely involving the afore-mentioned TLS), you may simply reuse them in order to establish a symmetric key for actual file encryption/decryption. Password-based encryption would fit for this purpose, if you want to avoid asymmetric crypto at all. Things get even more complicated if you also want to ensure integrity of the already confidential data, that is, you want to give a kind of guarantee to the authenticated and authorized user in the sense that what they finally access has not been altered in any way in the meantime.
Developing a solution for this will be no trivial task and depend to a large extent on your given requirements, so I'm afraid there's no "golden way" that suits everyone. I would suggest to do some research, get a clearer picture of what you are trying to achieve and how, then try to get additional advice on subjects that you still feel uncertain/uncomfortable with.
Symmetric Encryption is definitely fast and has excellent support for streaming of very large files.
SymmetricEncryption::Writer.open('my_file.enc') do |file|
file.write "Hello World\n"
file.write "Keep this secret"
end
Symmetric Encryption is designed for encrypting data and large files within an organization.
When it comes to sharing files with other organizations then the best option is PGP. For streaming of very large files with PGP consider: IOStreams
IOStreams.writer('hello.pgp', recipient: 'receiver#example.org') do |writer|
writer.write('Hello World')
writer.write('and some more')
end
Look at the file iostreams/lib/io_streams/pgp.rb for more PGP examples. It also supports PGP key management directly from Ruby.
I made a gem to help with this. It's called cryptosystem. Simply configure the path and password to your private key as well as the path to your public key, and it does the rest.
Encrypting is as simple as:
rsa = Cryptosystem::RSA.new
rsa.encrypt('secret') # => "JxpuhTpEqRtMLmaSfaq/X6XONkBnMe..."
And decrypting:
encrypted_value = rsa.encrypt('secret') # => "Y8DWJc2/+7TIxdLEolV99XI2sclHuK..."
rsa.decrypt(encrypted_value) # => "secret"
You can check it out on GitHub or RubyGems.

Should we use a module with constants to define Rails app API params?

Is there a pattern or best practice in Rails whereby we can specify, in one place, the names/symbols of params that are to be used in the API, so that we can reference it throughout our code and tests?
Our application entails a user passing in parameters to our API via HTTP POST. We use symbols to get at the values as follows:
first_name = params[:firstname]
last_name = params[:lastname]
...
We also set the values of params within our RSpec tests:
params = {
firstname: 'John',
lastname: 'Doe',
...
}
Obviously the above examples are rather simplistic, and in our application we have many more parameters. As such it would be good to have a definitive set of API parameters that can be used. The main benefit being that other developers can then know what parameters are available in the application. Furthermore, we want to safeguard against symbols being typed incorrectly.
My thinking at the minute is to use a module called API with some constants defined:
Module API
FIRST_NAME = :firstname
LAST_NAME = :lastname
...
end
We could then use the module as follows:
first_name = params[API::FIRST_NAME]
last_name = params[API::LAST_NAME]
...
Is this approach even correct? Will there be a performance cost?
Note: We will have the same parameters for every call. Furthermore, the parameters may change as we're currently in the early stages of development and the final set of API fields along with their names haven't been decided on yet.
It is likely your API will not have the same parameters for every call. Also, you probably won't want to change the parameters frequently unless you are the only consumer of your API as changes in the API will break things for your customers. For these reasons I don't think constantizing the params in a module is going to buy you that much.
While there are plenty of places to try to remove redundant code, I'm doubting that your proposed strategy is going to work well for you in the long term. If you find you are repeating yourself a lot in your tests (which certainly happens with APIs), you may want to take a look at rack-test-rest, a gem which can take care of a lot of the pain of API testing.
Basically it makes reasonable assumptions about arguments you don't provide to keep you on track for code http status codes, responses, etc. Hope this helps!

Which characters in a search query does Google ignore (versus treating them as spaces?)

I want to give my pages human-readable slugs, but Rails' built-in parameterize method isn't SEO-optimized. For example, if I have a post called "Notorious B.I.G. is the best", parameterize will give me this path:
/posts/notorious-b-i-g-is-the-best
which is suboptimal since Google construes the query "Notorious B.I.G." as "Notorious BIG" instead of "Notorious B I G" (i.e., the dots are removed rather than treated as spaces)
Likewise, "Tom's fave pizza" is converted to "tom-s-fave-pizza", when it should be "toms-fave-pizza" (since Google ignores apostrophe's as well)
To create a better parameterize, I need to know which characters Google removes from queries (so I can remove them from my URLs) and which characters Google treats as spaces (so I can convert them to dashes in my URLs).
Better still, does such a parameterize method exist?
(Besides stringex, which I think tries to be too clever. 2 representative problem cases:
[Dev]> "Notorious B.I.G. is the best".to_url
=> "notorious-b-dot-i-g-is-the-best"
[Dev]> "No, Curren$y is the best".to_url
=> "no-curren$y-is-the-best"
I would try using a gem that has been designed for generating slugs. They often make good design decisions and they have a way of updating the code for changing best practices. This document represents Google's best practices on URL design.
Here is a list of the best gems for solving this problem. They are sorted by rank which is computed based on development activity and how many people "watch" changes to the gems source code.
The top one right now is frendly_id and it looks like it will generate good slugs for your use in SEO. Here is a link to the features of the gem. You can also configure it and it looks like it is perfect for your needs.
Google appears to have good results for both the "b-i-g" and "big" in the url slugs.
For the rails side of things, yes a parameterize method exists.
"Notorious B.I.G. is the best".parameterize
=> "notorious-b-i-g-is-the-best"
I think you can create the URLs yourself... something like
class Album
before_create :set_permalink
def set_permalink
self.permalink = name.parameterize
end
def to_params
"#{id}-#{permalink}"
end
end
This will create a url structure of:
/albums/3453-notorious-b-i-g-is-the-best
You can remove the id section in to_params if you want to.
Use the title tag and description meta tag to tell google what the page is called: these carry more weight than the url. So, leave your url as /posts/notorious-b-i-g-is-the-best but put "Notorious B.I.G. is the best" in your title tag.

Resources