How would it be written using REST? - ruby-on-rails

I am making a browser game, it's completely AJAX-based, so I am trying to create a proper RESTful API.
So, I have a User model (basically, User has weapon, health and action points).
So I have a users resource. Now, I want to implement user attacks.
Scenario: user with id = 1 attacks user with id = 2.
What I would do is like this:
Send the following info (with POST-request):
target_id (well, it's stored in ApplicationController from session)
attacker_id
weapon_id (weapon attacker uses to attack his target)
to /users/attacker_id/attack/
Validate if user has enough action points and health for attack, if target is not dead yet. If these conditions fail - do nothing, if they succeed - decrease attackers action points and ammo, decrease target HP. All of this is done in model method called attack for attacker.
Is it a proper way in general or if there is a better, Rails way?
Thank you!

REST really makes the most sense when what you're doing are resource-based CRUD interactions. You're not really doing that in this case--you can sort of conceptually force it to conform, but I think you'd end up adding unnecessary and unintuitive complexity.
I'd say you just don't use REST. Just have an attack action that takes the params and does the rest.

Related

Two "access codes" instead of "username" and "password"?

The information system I sometimes use has 2 access codes that are password-masked.
Is this just a security through obscurity measure (being able to punch in username and password in front of audience) or does it have any other advantage over the conventional user/pass or token/secred?
I'm considering this when building my own IS for my business partners and myself. Is this any good or just annoying and useless unmemorable stuff for the user?
If it is a good idea, how to implement that with user.authenticate()?
I would not implement such a system, because..
The username/ID (first "access code") need not be a secret; while it should not expose confidential information (defined by policy), the purpose of this key is not to "add security" and making it hard to remember would annoy people - at least, it would annoy me.
If a user has to write down a "secret" because it is too hard to remember .. then anyone with access to the recording (e.g. text file, Post-It note) has access to the might-not-be-a-secret secret.
The way to increase security with passwords (second "access code") is to encourage passphrases, which are can be easier than "P#ssw0rds!" to remember (and are much easier than random passwords to remember!), but much harder to brute-force. It is the password/pass-phrase which is the secret token.
Assuming the use of proper connection encryption and using sound bcrypt/scrypt password hashing (and not suffering from an attack vector such as Heartbleed or a local keysniffer), then the next consideration is to mitigate brute-force attacks.
I would focus on using a solid (exiting and proven) authentication implementation, and secure server management and key policy.
That being said, here are additional thoughts ..
It might be useful/relevant to make the username/ID (first "access code") field masked, like a password field. This can prevent cases where the password/pass-phrase is accidentally exposed when entered into a username/ID field, as when such authentication is done in front of a live audience. (I've seen this mistake done several times.)
However the goal is not to add security, excepting that it can mitigate accidents, as the username/ID is not a password: it is not "encrypted", hashed, or otherwise considered a secret.
Using an additional credential provider (e.g. RSA fob, or smart card/fingerprint/pub-private keys) can be used in such cases where increased security is required. Appropriate use of such is much more secure than "two passwords".
In terms of security, access codes are probably slightly more secure than user & pass, considering they're encrypted correctly. This is my opinion
For Rails, you will have to remember 3 important factors:
Who's using your system
How will they engage with the authentication area
Are you using with any other system (such as Devise)?
--
Public Keys
If you're looking to create a preview mode of sorts, I would create a series of API keys, which you'll be able to use to gain limited functionality to the app.
We do that like this:
#users table
id | public_key | other | information | created_at | updated_at
#app/models/concerns/token.rb
module Token
extend ActiveSupport::Concern
included do
before_create :generate_token
end
protected
def generate_token
self.public_key = loop do
random_token = SecureRandom.urlsafe_base64(10, false)
break random_token unless self.class.exists?(public_key: random_token)
end
end
end
#app/models/user.rb
include Token
I found this code somewhere (I forgot where unfortunately), but it basically uses the before_create callback to populate the public_key attribute of your User model.
The public key is created using the SecureRandom method

Security impact of using constantize

I'm currently reviewing some Rails controller. That controller takes user input and based on that user input a new object is created like so:
clazz = params[:type].classify.constantize
clazz.new(some_method_which_returns_filtered_params)
I'm concerned with the security of this approach. Are there classes in Ruby which the 'new' method could be used with malicious intent?
For example it might be possible to flood the program with new Symbols causing a denial of service (see http://brakemanscanner.org/docs/warning_types/denial_of_service/).
I'd recommend limiting the values that this code will accept for params[:type], before executing it. Eg with an if block like
if %w(foos bars bazzes).include?(params[:type])
clazz = params[:type].classify.constantize
clazz.new(some_method_which_returns_filtered_params)
end
I don't think DOS attacks are a specific problem with doing classify.constantize here: if someone spams your server with requests then that's going to DOS attack you whatever you do in the actual controller.
Preventing DOS attacks is hard. Securing web apps is a massive subject, but in particular you seem to be talking about the area of "sanitizing parameters" here. Have a look at
http://guides.rubyonrails.org/security.html
I can't resist linking to this classic XKCD strip: http://xkcd.com/327/

Why not refer to the session hash in the Model layer?

This question has been repeatedly asked and answered with one-line assertions, such as "because it is an obvious violation of MVC." Frankly, I just don't get it. Indeed, it feels to me that putting session inside the controller merely an artifact that ApplicationController faces the network layer via a rack call, rather than an MVC mandate. Let me explain my problem.
Rolling an authentication from scratch, I found myself agonizing and spiking all over the place for lack of ability to articulate simple tests (session isn't available to the testing framework either). My authentication scheme, as almost all I have seen in rails, wanted to use the session hash as a persistence layer to retain the id for the User model of the "current user." Doesn't that feel FAR MORE like a model than a controller artifact?
The code smells are obvious whenever you look at the "typical" sessions controller (this one from Ryan Bates excellent screencasts). Desperate to shovel this concept in with rest, we see unhealthy language such as:
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
To me, this is a code smell, an obviously overlogicked controller that is screaming for refactoring! But we can't. Why? Oh yes, because it is a violation of MVC to put references to the session, used as a persistence lawyer into the model. WTF? Doesn't it say something to you that we seem to want to CALL THIS REST RESOURCE /sessions?
To see why this is just plain screwy, look at your login views -- hand-coded html, or use of the "_tags" API? If we had an ActiveModel model to do this code, then the create code could look like the usual scaffolding, or possibly even reduced to the "respond_with" one-liner.
def create
recognition = Recognition.new(params[:user])
if recognition.save
redirect_to root_url, :notice => "Thank you for signing up!"
else
render "new"
end
end
Then, take a look at the hand-coded html for all of those views! If Recognition was a model, persisted by session (or some other means that should not be the responsibility of the controller layer anyway), then you could simple use form builder or simple_form to generate the forms. Of course, we could simply pass the session hash to a "new_login" class method of Recognition, say Recognition.on(session).new(params[:recognition]), but that seems uglier than it has to be. Perhaps it is inherent, as we will want to use a current_user reference later in the application layer, perhaps Recognition.on(session).current_user similar to the way one might use a singleton pattern?
Just try to build your authentication package with strict BDD, and honestly tell me you haven't spiked this portion of it? If we had a Recognition model, this entire thing would be reduced to a simple set of unit tests without hackery. Now, instead we have the "sole" use case for integration testing, magic invasions of ActiveController modules and hacks to make speedy any acceptance testing of the logged_in_as predicate.
I think the entire point of ActiveModel was to facilitate this kind of rethinking and refactoring. Not all models use "the" database. Why not persist to the "session?"
I have been using devise and its kin for too long, burying these smells with the "dont mess with the gem" excuse I don't have to look at them. No longer! I think I am going to reject the zealots from now on. Sorry, to me, session is a persistence layer that should be manipulated in the Model layer of MVC. I posit, but am not sure, that the reason it lives in controllerland has more to do with the ugly or elegant fact that controllers are rack objects than any theoretical MVC magic.
So once again, is there a more elegant way to access the session layer than to have logic in the controller for that?
Maybe it's just me, but I don't sniff the code smell in that controller. I guess it depends on what you think should go into controllers versus models.
I think people take the "skinny controllers" idea to an unhealthy extreme at times. Yes, you want everything that can be in a model to be on the model: but controllers exist to change models based on application state, and you should allow them to fulfill that design goal. Having every controller be something like:
def create
Creator.create(params) # Pass all params to the creator model, which will automatically detect what object you're trying to create, make it, and then render the appropriate view
end
def show
Shower.show(params) # Find the model object and the view based on the params and render them together
end
Defies the idea of separation of concerns and creates nightmarish problems for people trying to update and maintain your code. Controllers should call model objects and even methods on those models to create and persist application state, and models should be agnostic to the state of the application. If you couple them together too tightly you'll end up with view and controller code in your models, at which point it becomes very difficult to determine what's where in your application.
If this is what you want and you think it serves your goals, then go for it -- but your code will be more difficult to maintain and will be hard for other people to understand. MVC exists because it's a sensible way to separate concerns and makes your code less surprising for other people.
All of this said, the session model you're proposing is actually a pretty good idea... and hence, it already exists. ;) The authlogic framework has a Sessions model: when logging in using authlogic, you create a new UserSession with the params object. UserSessions live in the models folder and exist solely to abstract away the nitty gritty of authentication into a controller-aware model class, so if that's what you're looking for, it's already been done for you! Go check out the authlogic github repository for documentation and usage examples.
I would still shy away from passing any kind of controller state into a real ActiveRecord model though. Allow your controllers to manipulate models and render the results of that manipulation as HTML -- it's what they're there for!

Prevent modification ("hacking") of hidden fields in form in rails3?

So lets say I have a form for submitting a new post.
The form has a hidden field which specify's the category_id. We are also on the show view for that very category.
What I'm worried about, is that someone using something like firebug, might just edit the category id in the code, and then submit the form - creating a post for a different category.
Obviously my form is more complicated and a different scenario - but the idea is the same. I also cannot define the category in the post's create controller, as the category will be different on each show view...
Any solutions?
EDIT:
Here is a better question - is it possible to grab the Category id in the create controller for the post, if its not in a hidden field?
Does your site have the concept of permissions / access control lists on the categories themselves? If the user would have access to the other category, then I'd say there's no worry here since there's nothing stopping them from going to that other category and doing the same.
If your categories are restricted in some manner, then I'd suggest nesting your Post under a category (nested resource routes) and do a before_filter to ensure you're granted access to the appropriate category.
config/routes.rb
resources :categories do
resources :posts
end
app/controllers/posts_controller
before_filter :ensure_category_access
def create
#post = #category.posts.new(params[:post])
...
end
private
def ensure_category_access
#category = Category.find(params[:category_id])
# do whatever you need to do. if you don't have to validate access, then I'm not sure I'd worry about this.
# If the user wants to change their category in their post instead of
# going to the other category and posting there, I don't think I see a concern?
end
URL would look like
GET
/categories/1/posts/new
POST
/categories/1/posts
pst is right- never trust the user. Double-check the value sent via the view in your controller and, if it does't match something valid, kick the user out (auto-logout) and send the admin an email. You may also want to lock the user's account if it keeps happening.
Never, ever trust the user, of course ;-)
Now, that being said, it is possible to with a very high degree of confidence rely on hidden fields for temporal storage/staging (although this can generally also be handled entirely on the server with the session as well): ASP.NET follows this model and it has proven to be very secure against tampering if used correctly -- so what's the secret?
Hash validation aka MAC (Message Authentication Code). The ASP.NET MAC and usage is discussed briefly this article. In short the MAC is a hash of the form data (built using a server -- and perhaps session -- secret key) which is embedded in the form as a hidden field. When the form submission occurs this MAC is re-calculated from the data and then compared with the original MAC. Because the secrets are known only to the server it is not (realistically) possible for a client to generate a valid MAC from the data itself.
However, I do not use RoR or know what modules, if any, may implement security like this. I do hope that someone can provide more insight (in their own answer ;-) if such solutions exist, because it is a very powerful construct and easily allows safe per-form data association and validation.
Happy coding.

Steps to create my own authentication system, need some guidance

I want to learn how to create my own authentication system, please provide some guidance if am doing this wrong.
I will create a Module in my /lib folder /lib/auth.rb
I will require this module in my ApplicationController.
when a user enters their email + password, I will call a method that will do a lookup in the user's table for a user with the same email, I will then compare the passwords. (i'll add encryption with salt later).
If the user entered the correct credentials, I will create a row in the Sessions table, and then write the session GUID to a cookie.
Now whenever I need to check if the user is logged in, or I need the user object, I will check if the cookie exists, if it does, I will lookup the session table for a row with the same guid, if it exists, I will return the session row and then load the User object.
I realize there are many suggestions one can give, but in a nutshell does this sound like a workable solution?
Now to make this usable, I will have to make some helper methods in my ApplicationController right?
How will I access the current_user from within my views?
P.S I know of other authentication systems, I just want to learn how to create my own.
The basic logic you're following is correct. Of course you can always expand on this with features that you need. For instance, you'll need helper methods for things like "logged_in?" and "current_user". Also, you might want to add session expiry, or session retention as a "remember me" feature.
Go for it, you won't learn authentication systems better than building your own then figuring what's wrong with it.
You should really check out the authlogic gem on github.
http://github.com/binarylogic/authlogic
It also has great instructions on how to set up your users.
After Faisal said what I would say, I only give you answer to the last part of your question:
"How will I access the current_user from within my views?"
try something like this:
class User < ...
def self.current=(u)
#current = u
end
def self.current
#current
end
end
In your views (or any part of your code) you can call User.current. Your controller has to assign a validated user to User.current. Your filters can react to "if User.current.nil?" and so on.
If you want to be thread safe, you may use a thread variable instead of #current:
Thread.current[:current_user] = u

Resources