I'm very new to Spring. I'm trying to create a REST API using Spring Boot and I'm stuck whether to expose my user's primary key or not which also happens to be their email. Something like api/user/example#gmail.com. A big part of me says it's okay since it would sensible to expose it as it is the identifier for that specific record when viewing, deleting, and updating. Is there a security risk for this? What is the best practice for such implementation? Right now I'm combining the #PathVariable and #RequestBody. I didn't like the idea of putting my primary key in the RequestBody thinking that it might pose a risk...or is there?
#RequestMapping(value = "/updateUser/{customerEmail}", method = RequestMethod.POST)
public ApiResult updateCustomer(#RequestBody UserDetailsDto userDetailsDto, #PathVariable String customerEmail) {
//service call...
}
First of all, user e-mail is often considered to be PII (Personally Identifiable Information). As such it would be unwise to put it into a URL, because you should not put any sensitive information into the URL. Header - ok, body - too. But not into the URL. The reason is, that all the proxies/load balancers/other infrastructure you have or might have in the future will always be allowed to log URLs for debug reasons. And you don't want your sensitive data to leak across the components like this. No company policy would ever allow that.
Spring is a good framework of choice, usually as long as the identifier is unique it should be fine, the problem with using an email is you are exposing your users data more easily which could be problematic to the users, I would suggest you rather use a string of unique characters as an identifier in the form of:
http://api.example.com/user-management/users/{id} as an example http://api.example.com/user-management/users/22
in this case identifier of user 22 has the email example#gmail.com in this way you are not exposing sensitive data when doing an update here is a link that gives guidance on best naming practice https://restfulapi.net/resource-naming/.
Another tip given in the link provided is to avoid using URI's as CRUD (Create, Read, Update, Delete) functionality "URIs should be used to uniquely identify resources and not any action upon them".
Any sensitive information (in this case email but in other case that could also be your database autoincremented primary key field ID in your table) should not be exposed.
Once way to go around that that I know and I use is to have 2 fields. For example, I have table USER {ID, USERID, NAME, ...}
Above, ID is autoincremented Long field representing PK.
USERID on the other hand, is a field generated of random characters or GUID which I use to pass back and fort in REST calls.
So, I might have record in USER table as:
USER {1, "a23asf60asdaare998700asdfasr70po097", "Mike", ...}
If I were to pass ID=1 back and forth, a malicious user could easily deduce what it is and how to query next user. For that reason, i pass USERID which represent a public and safe version of ID that can be passed and no one can know what would be the USERID of next user.
So, your response model, dto model etc should have these fields and response model should return USERID instead of returning ID. And you can use JPA to find the user by the USERID (so, based on that, that method must be called in this case findByUserId).
The same would apply for your case where you use email instead of ID if you want dont want to expose user emails which make sense to me.
Hope that helps.
I think it's more a matter of taste and personal beliefs rather than objective aspects.
Since HTTPS is more or less mandatory today, it's a lot harder to obtain the e-mail address by just sniffing with a tool like Wireshark.
So what's the possible risk? Since users have to be authorized to call this endpoint, they know at least their own e-mail address and most likely used it to authenticate. So a user can't modify or acquire the data of another user, if properly implemented.
A problem which may be of concern is that it might be possible to check for a registered e-mail during the registration process. Depending on what kind of application you're developing, this might be an issue. To give a brief example of such a case: Imagine a catholic priest registered on a porn site or the e-mail address of your husband/wife registered on a dating platform.
So may advice: Force HTTPS and you are pretty fine to use them as a primary key. However, if you have the possibility to abstract this, I'd do so. A numerical key or username may be a better choice and also easier to handle - but it makes no difference. Imagine if you have an endpoint to acquire the user's data, including e-mail address. It just doesn't matter if you acquire this data by a numerical key or by the e-mail address. In the end, you end up with the e-mail address in the response's body. And if this body is accessible by someone, he can also access the username and password, thus rendering any security measurement you've taken useless.
Related
I am curious if there is a way to store some user data on my request which will come back to me on the returned data. For example, I am sending several requests for let's say 3 different orders. They might be for the same symbol, but depending on the order I will be getting different types of data. Is there a way that I store the order ID on the outgoing message request and have it come back to me on the return? I see there is a Session.sendRequest call where you can specify a requestLabel, but I don't see it coming back on the returned message so I'm not sure what this is for.
Thank you in advance!
It looks like the correlation ID is exactly what is needed. I can create a unique correlation ID for each order request based on the order ID and some unique string (for me, a count is sufficient). Then I can parse out the order ID piece when it is returned. I'm still not fully sure what requestLabel is for, but I don't think I need it for this requirement.
I think it'd be up to you and your app, not Bloomberg. I'll bet Bloomberg is idempotent - it treats every request that comes in as if it's the first one ever.
The Session is a variable on your side that's created when a user logs in. You'd create the label or some other unique tracking GUID and keep it in session. Every request that user sends out during that Session would be associated with that session ID>
Is it a bad practice to expose DB internal IDs in URLs?
For example, suppose I have a users table with some IDs (primary key) for each row. Would exposing the URL myapp.com/accountInfo.html?userId=5, where 5 is an actual primary key, be considered a "bad thing" and why?
Also assume that we properly defend against SQL injections.
I am mostly interested in answers related to the Java web technology stack (hence the java tag), but general answers will also be very helpful.
Thanks.
That bases on the way you parse the URL. If you allow blind SQL injections that is bad. You have to only to validate the id from the user input.
Stackexchange also puts the id of the row into the URL as you can see in your address bar. The trick is to parse the part and get did of all possible SQL. The simples way is to check that the id is a number.
It isn't a bad thing to pass through in the URL, as it doesn't mean much to the end user - its only bad if you rely on that value in the running of your application. For example, you don't want the user to notice that userId=5 and change it to userID=10 to display the account of another person.
It would be much safer to store this information in a session on the server. For example, when the user logs in, their userID value is stored in the session on the server, and you use this value whenever you query the database. If you do it this way, there usually wouldn't be any need to pass through the userID in the URL, however it wouldn't hurt because it isn't used by your DB-querying code.
To use the database ID in URLs is good, because this ID should never change in an objects (db rows) life. Thus the URL is durable - the most important aspect of an URL. See also Cool URIs don't change.
Yes it is a bad thing. You are exposing implementation detail. How bad? That depends. It forces you to do unneeded checks of the user input. If other applications start depending on it, you are no longer free to change the database scheme.
PKs are meant for the system.
To the user, it may represent a different meaning:
For e.g.
Let's consider following links. Using primary-key,it displays an item under products productA, productB,productC;
(A)http://blahblahsite.com/browse/productA/111 (pkey)
(B)http://blahblahsite.com/browse/productB/112 (pkey)
(C)http://blahblahsite.com/browse/productC/113 (pkey)
User on link B may feel there are 112 items under ProductB, which is misleading.
Also it will cause problem while merging tables since PK will be auto-incremented.
I'm looking to use Google's App Engine (Java) to provide the backend to an Android messaging app I'm currently writing, I'm just starting out with GAP but have a little experience with Java (through Android).
The first time someone uses the app it will send some sign-up data to the server, this will stored in the GAE datastore, and a unique id returned to the phone (or an error message if something broken).
As I can't see something that looks like key = datastore.giveMeAUniqueKey or datastore.hasThisBeenUsedBefore(key) I guess I'm going to have to generate a random key and see if it's been taken (I'm not that sure how to do that to be honest).
Any ideas (either answers to the specific question, or pointer to useful "getting started" resources)?
Thanks.
If this value is not security sensitive (ie, it's just a user ID and you have some other method to authenticate the phone), just do an insert and take the key of the newly inserted entity. The datastore will assign a guarenteed-unique key automatically if you insert a new entity without providing one. Alternately, you can explicitly request an ID with the allocate_ids call.
If the value is security sensitive (it's a session nonce or something used for authentication), use the SecureRandom class to generate a sequence of random bytes. Do not use this as a key for an entity such as a user object; this would preclude changing the session ID if the user's session is compromised. Have a separate user ID used for that purpose, and use this secure nonce only for the authentication step.
Note that simply looping creating IDs, testing for conflicts, and inserting is not safe without using a transaction; it's easier (and faster, and cheaper...) just to use app engine's built in ID assignment system.
I got similar domain model
1) User. Every user got many cities. #OneToMany(targetEntity=adv.domain.City.class...)
2) City. Every city got many districts #OneToMany(targetEntity=adv.domain.Distinct.class)
3) Distintc
My goal is to delete distinct when user press delete button in browser. After that controller get id of distinct and pass it to bussiness layer. Where method DistinctService.deleteDistinct(Long distinctId) should delegate deliting to
DAO layer.
So my question is where to put security restrictions and what is the best way to accomplish it. I want to be sure that i delete distinct of the real user, that is the real owner of city, and city is the real owner of distinct.
So nobody exept the owner can't delete ditinct using simple url like localhost/deleteDistinct/5.
I can get user from httpSession in my controller and pass it to bussiness layer.
After that i can get all cities of this user and itrate over them to be sure, that of the citie.id == distinct.city_id and then delete distinct.
But it's rather ridiculous in my opinion.
Also i can write sql query like this ...
delete from
t_distinct
where
t_distinct.city_id in (
select
t_city.id
from
t_city
left join t_user on t_user.id = t_city.owner_id
where
t_user.id = ?
)
and t_distinct.id = ?
So what is the best practice to add restrictions like this.
I'm using Hibernate, Spring, Spring MVC by the way..
Thank you
What you're asking for is not SQL Injection prevention. You need to ensure the user attempting the deletion is authorized.
As long as you check that the user accessing the page has the rights to delete the row your trying to delete (this would be checked in the Business layer), and ONLY allow the delete command if the user is authenticated and authorized to perform the action.
With hibernate you don't have to worry about sql injection. It always uses prepared statements, so you are safe.
As for your concrete case, this is not an sql injection. But to prevent it, make validation in the controller - whether the currently logged user owns the desired ID.
Depending on the size of the application, you can implement some general security scheme, with ownership settings, and apply it (using AOP).
I understand that i want to be sure, the the user is real owner of Book The question was how to accomplish it. And yes, i know that user is authenticated and authorized. But another authorized user can easy delete pages of another user.
This can be done like this...
User userFromHttpSession ...
Long bookId = load page, get bookId, load book, get bookId
List books = userFromHttpSession.getBooks();
... iterate over books and find out if one of the book.id == bookId
... then if book owner is owner of httpSession, then proceed Delete
It's like too many sql queries, and too many code, probably there are better solution. Anyway thank you for your answers
Just use your head, quote-escape* everything from an outside (or inside for that matter) source before it gets put in an SQL statement, and check data as it goes in. Or, use prepared statements.
*Edit: By "quote-escape" I meant functions like PHP's mysql_escape_string()
I'm using OpenID. How do I make it so that the user stays logged in for a long time even after closing the browser window?
How do I store and get access to the user's User object?
Basically, I guess I just don't really understand how sessions work in Java.
So you actually want like a "Remember me on this computer" option? This is actually unrelated to OpenID part. Here's a language-agnostic way how you can do it:
First create a DB table with at least cookie_id and user_id columns. If necessary also add a cookie_ttl and ip_lock. The column names speaks for itself I guess.
On first-time login (if necessary only with the "Remember me" option checked), generate a long, unique, hard-to-guess key (which is in no way related to the user) which represents the cookie_id and store this in the DB along with the user_id. Store the cookie_id as cookie value of a cookie with known cookie name, e.g. remember. Give the cookie a long lifetime, e.g. one year.
On every request, check if the user is logged in. If not, then check the cookie value cookie_id associated with the cookie name remember. If it is there and it is valid according the DB, then automagically login the user associated with the user_id and postpone the cookie age again and if any, also the cookie_ttl in DB.
In Java/JSP/Servlet terms, make use of HttpServletResponse#addCookie() to add a cookie and HttpServletRequest#getCookies() to get cookies. You can do all the first-time checking in a Filter which listens on the desired recources, e.g. /* or maybe a bit more restricted.
With regard to sessions, you don't need it here. It has a shorter lifetime than you need. Only use it to put the logged-in user or the "found" user when it has a valid remember cookie. This way the Filter can just check its presence in the session and then don't need to check the cookies everytime.
It's after all fairly straight forward. Good luck.
See also:
How to implement "Stay Logged In" when user login in to the web application
How do servlets work? Instantiation, sessions, shared variables and multithreading
Well, the original reason I chose OpenID was so someone else could handle as much of the implementation and security of authentication for me.
After looking into OpenID more, it appears there is something called an "Immediate Request" (http://openid.net/specs/openid-authentication-2_0.html#anchor28).
When requesting authentication, the Relying Party MAY request that the OP not interact with the end user. In this case the OP MUST respond immediately with either an assertion that authentication is successful, or a response indicating that the request cannot be completed without further user interaction.
Because of this I think I could just store the user's openID url in the cookie, and use an immediate request to see if the user is authenticated or not. This way I don't have to do anything with my database, or implement any logic for preventing session hijacking of the long-lived cookie.
This method of doing it seems to be the way OpenID suggests to do it with their Relying Party Best Practices document.