i'm having a little problem with my phonegapp app on Android with python-django as backend. When i close the app i lost all the cookies that the server sets after the authentication (sessionid and csrftoken).
So, every time i open the app i have to do the login procedure. I try to save the sessionid in localStorage and then create my own header but this is not allowed by XMLHttpRequest specification. I need a simple workout for doing something like this:
function get_csrf_token(){
$.ajax({
url:"http://www.mywebsite.com/token",
type:"GET",
dataType:"text",
beforeSend: function(request) {
request.setRequestHeader("Cookie", 'sessionid=' + window.localStorage["sessid"]);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(JSON.stringify(XMLHttpRequest));
alert(JSON.stringify(textStatus));
alert(JSON.stringify(errorThrown));
},
success: function (token) {
window.localStorage["token"] = token;
return token;
}
});
}
Is this possibile with phonegap or i have to login every time i start the app?
You really aught to be using a different authentication method when dealing with mobile. It's a lot easier to try token-based authentication. Essentially you have a form on your mobile app that takes their username/password and pass it to a view you design that ensures validity and then responds with a token that the app can include in all subsequent calls.
You can implement this in Django fairly easy with a custom authentication backend, or you can use Django Rest Framework http://www.django-rest-framework.org/api-guide/authentication#tokenauthentication that has it built in.
What you're doing is definitely possible. It's impossible to set cookies on an XMLHttpRequest object. But if you set the cookie using document.cookie first, it will be sent on the cookie header for every subsequent request.
function get_csrf_token(){
document.cookie = 'sessionid=' + window.localStorage["sessid"];
$.ajax({
url:"http://www.mywebsite.com/token",
type:"GET",
dataType:"text",
...
});
}
The only thing you are going to want to watch out for while doing this is the possibility of an XSS attack. By storing the session id in localstorage, if your app were to have an XSS vulnerability, an attacker could possibly get the localstorage session id and send it to their server using JSONP or an image tag etc. Since you are using phonegap, you can mitigate this problem by using a whitelist policy that will only allow requests to go to your known servers.
Related
I'm working on an android apps. I am using ionic framework. In some pages I need to get data from a web server and the result is an object json.
My problem is if some one arrives to GET the pages where I get the json data, one can fetch all my database data by changing the http request.
Is there any way that can improve security of my apps?
You should make some kind of authentication mechanism, for example, a token in the header, that way you know wether the user has access to that resource or not.
So when you make your request you can generate a configuration for that particular request.
Example:
var url = "http://yourserver.com/api/your/path";
var config = {
"headers": {
"Authorization": "Bearer someBearerFromTheServer"
}
};
$http.get(url, config);
The backend implementation for this to work depends on the language you use. Here google is your best friend.
A more advanced way to do this, is to use interceptors in the $http service and attach the token to the header in every request, but be careful, you should secure this so you won't send your credentials to every request you make (sometimes your app might need to request data from another server).
You can read more about $http services and its configurations in the $http service documentation.
Regards
I am currently working on implementing a mobile app for our site that uses Ruby on Rails and Devise. The idea here is, at first, create a mobile login form that on successful login opens a web frame that is authenticated and allows the normal use of the (mobile optimised) site. Theoretically that should be possible.
I am having trouble with the following issues:
How do you get the pure session key for the user session via a json request? What methods can be used to manually generate it from devise, something that the sign_in(:user, user) method does?
Is it even possible to take that key and put it into the browser cookie the way it normally happens in devise, but on the mobile side?
I know that this is not the standard method of making mobile applications for the site, but I believe it should be possible.
You might want to consider using Devise Token Auth and treating your mobile application like just another webapp that requests permission from your main site. DTA is particularly nice since it takes care of managing the session tokens (renewing/expiring) and passing them onto the app requiring access. The issue is overriding your session controllers so that it automatically logs in after you already log in on the mobile app (or just rewriting your log in so it occurs in conjunction with the Rails site, rather than before). Considering you're already using Devise, this may also be more refactoring than you'd like.
If you want to put your authentication form on the mobile UI and pass the credentials over to the web frame, you need a way to pass data from the mobile app to the web frame.
How you accomplish this depends on what platform you're building on. I'm not really a mobile developer so I don't know for certain how difficult / easy these options are:
When opening the web frame, instantiate it with session data
Find a way to call methods on the client from the web frame. Something like getSessionData.
You could generate a fingerprint for the web frame, have the mobile UI send this data to the server, and then have the web frame authenticate with the server by sending the fingerprint.
Again, I'm not entirely sure how possible all these options are.
You should use token authorization and Android deep linking. It will allow you to login in the web browser and send a token to your app via deep linking.
OK, so I decided to make a webframe solution as follows, basically you post the login and password to a certain sign_in method specially designed to generate one-time sign in tokens for the application. You need two methods in the system to do that:
routes.rb
devise_scope :user do
get "sign_in_with_token/:token" => "sessions#sign_in_with_token"
post "get_login_token" => "sessions#get_login_token"
end
sessions_controller.rb (don't forget to add the method that increases the failed_sign_in_count on wrong password, otherwise that can allow brute force attacks)
def get_login_token
user = User.find_by_email(sign_in_params["login"])
password = sign_in_params["password"]
if user and user.valid_password?(password)
token = SecureRandom.hex(16)
user.update_attribute(:authentication_token, token)
render json: {token: token}, status: 200
else
render json: {error: "error"}, status: 403
end
end
and the method to sign in with that token
def sign_in_with_token
#user = User.where(authentication_token: params[:token], email: Base64.decode64(params[:email])).first
if #user
#user.update_attribute(:authentication_token, nil)
sign_in(#user, bypass: true)
end
redirect_to '/' # or user_root_url
end
That way the mobile app will work like this:
use the generic web frame to send ajax requests to the server and get that token for the user email if password is correct.
make a /sign_in_with_token/#{token from ajax}?email=#{base46 encoded email} link inside the app.
open that link inside the web frame and use the app as though you were logged in normally. Now the app can save email and password locally and use that logic to get the token again for another session. Later logging in will also be able to set the app id so that push notifications can be sent.
Appreciate any feedback or criticism on this solution.
I am very new to cordova developing. I am trying to develop one login page in android app, i need to access username and password from database for checking credential. Now i am hosting one web service and just pass the user name and password to that service using ajax request and proceed based on value returned from webservice. I dont know is this the correct procedure?. I am sending user name and password through ajax post, i think its insecure.Can you please suggest the best wasy to access database in cordova? I am using visual studio IDE for developing. I used following code to send username and pwd to webservice.
$.ajax({
url: 'localhost\service\Controller',// hostedd in iis
data: JSON.stringify({ username: 'user1', password: 'pwd' }),
sucess: function (data) {
//perform operation for login success
},
error: function () {
}
})
Thanks
Follow these steps:
If you use external urls, then white listen them:
http://cordova.apache.org/docs/en/dev/guide/appdev/whitelist/index.html
Use only https.
Verify the footprint of your cert by using this plugin:
http://plugreg.com/plugin/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin
Don't send the password, send the hash of the password. Use the same algorithm which you use in the backend for creating the hash.
Create a device UUID, save it on the device and send it to the backend and save it the first time, the device called the backend. Use this UUID for logging the device activity.
On every request to the backend, send the device UUID and check it.
Make sure, that you have a way in the backend to stop the activity of a device and user.
In some of my apps, I use the device UUID for individual encryption.
If you want, you can encrypt your whole app by using this plugin:
http://plugreg.com/plugin/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin
In some of my apps (B2B apps), I use an authorization which is working via QR code. In the backend I create some individual «secure Infos» and show them as an QR code. In the app you have a barcodescanner which scans the info , which is then saved on the device. Works great and this is a good way to have individual keys on the devices.
Hello all i am making an android app in whiich i have multiple account login at a time now my question is that i for multiple logins i should use sessions to verify every account user that is logged in. Now i am using express on the server side i have read a lot of documentation on storing sessions in node.js
Express-session (Though it is only good for development but not for production but not for my app)
Cookie-session
connect-Redis
connect-mongo
I have also heard about json web tokens where i can generate unique tokens and then i can pass the tokens to the client using res.json({user_id:"user1", token: "generated_token here"})
I have also heard about passport but dont know how it is going to do this also as in passport i use express-session by default will it be good for production or not ??
Now my first question is i have read all of there docs and nowhere it is mentioned where i am creating unique tokens for every user that is signing up.
Second question as i am using my server for android app there will be no use of cookie i will be sending user token as in parameter req.body.token now how to cmpare this with current user_id.
Actually i dont get the flow of control i mean how everything is going on in session in node.js. Also what is this secret is this thing generating unique tokens or what. Also i mean about 100000 of users are registered for my app now please tell me accordingly which way should i use for my app.
I have asked this question previously but there i did not mention that as i am not making a website how to do this(As in my case there will be no use of tokens)
I know this question i am asking is very vague but please bear with me i just want to understand how sessions are used in node.js
Thanks Anways
I'll try to answer this, but it is vague (as you pointed out). I'm going to make an assumption that your Android app is a native Android app and is going to be connecting to some sort of NodeJS backend in the cloud that is based on ExpressJS. If that's not the case, please clarify your thoughts in an update to your question.
The best idea for this specific scenario is to look to the cloud provide. Azure App Service Mobile Apps, for example, allows you to implement authentication - it eventually returns a JSON Web Token (http://jwt.io) to authenticate each request.
If you don't want to be beholden to a cloud provider, but want to run it yourself, you are going to have to implement the token generation and checking yourself. This generally follows the form:
Set up a WebAPI endpoint (maybe /signin) which takes whatever token the identity provider gives you, verifies the information and returns a JWT - there is an NPM module (jsonwebtoken) for producing the JWT. Ensure the JWT includes the identity of your user. I tend to use email address for the identity.
Your Android application will do a WebAPI request to your backend with an Authorization header, the value of which is "Bearer "
Your NodeJS API will use JWT authorization to validate the JWT and extract the user identity so you can use it in your API logic.
The important thing to note in this specific scenario is that your backend code is implementing a WebAPI - there are no cookies nor sessions in the API. The only thing that is linking the user from the client code to the backend code is the JWT.
As a short piece of code, here is how you verify a JWT:
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var jwtCheck = jwt({
secret: new Buffer('your-jwt-secret', 'base64'),
audience: 'your-jwt-audience'
});
app.get('/api/protected', jwtCheck, (req, res) => {
// Your code here
});
app.listen(process.env.PORT || 3000);
I have an ASP.NET MVC/Web API backend where I have implemented a Forms Authentication for my Phonegap app. The login is executed by sending the users credentials via jQuery Ajax call like this:
$.ajax({
type: "POST",
url: "/api/authentication/login",
data: JSON.stringify({ Username: username, Password: password }),
contentType: "application/json; charset=utf-8",
dataType: "TEXT",
statusCode: {
200: function (response, status, xhr) {
// successfully authenticated
Backbone.history.navigate("/", { trigger: true });
}
}
});
The backends login method looks like this:
[ActionName("login")]
[AllowAnonymous]
public LoginResult Login(LoginCredentials credentials)
{
// doing all kinds of things here
// if valid credentials
FormsAuthentication.SetAuthCookie(loginID, true);
return loginResult;
}
I have this in my Web.config:
<authentication mode="Forms">
<forms
name=".ASPXAUTH"
loginUrl="/login"
defaultUrl="/home"
protection="All"
slidingExpiration="true"
timeout="525600"
cookieless="UseCookies"
enableCrossAppRedirects="false"
requireSSL="true"
>
</forms>
</authentication>
Now the problem with Android here is that the cookie is properly set and it does work on my authorized methods after the login, but sometimes (often) when I close the app and open it again, I'm no longer logged in. The cookie isn't there anymore, I can not see it in the request. This should not happen because I have set the timeout to 525600. I have noticed that this problem often occurs when I close the app immediately after login. In other hand if I log out and then log in without closing the app, the cookie is saved properly.
But, if I get the cookie to stick, most of the time the logout behaves strangely as well. This is how I do the logout request:
$.ajax({
type: "POST",
url: "/api/authentication/logout",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "text"
success: function (response) {
// successfully logged out
Backbone.history.navigate("api/login", { trigger: true });
}
});
The backend:
[ActionName("logout")]
[AllowAnonymous]
public String Logout()
{
FormsAuthentication.SignOut();
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, "");
cookie.Expires = DateTime.Now.AddYears(-1);
HttpContext.Current.Response.Cookies.Add(cookie);
return "home";
}
Now similar to the problem with the login, the logout first seems to be successful and the cookie is no longer sent with any requests. But when I close the app and open it again, the cookie is back and I'm logged in again. I can see that the cookie has the same value as the one I thought I just removed by setting its expiration time to the past.
I have tried all kinds of tricks, like:
extra reloads after the login/logout (location.reload())
executing the logout/login request multiple times
executing request to other methods after the login/logout
1-10 second timeout between the login/logout request and the reload
all kinds of variations of the above
The authentication works as intended on iOS and Windows Phone. The problem occurs only on Android (tested on KitKat and Lollipop). No problem on the Android emulator, but on real devices and Visual Studios Android emulator this happens all the time.
I don't know in which direction to go from here. Is there something in the Android WebView that could cause this kind of behavior? Is there something else I could test out? Please help!
I'm more than happy to give more information if needed.
EDIT:
Inspired by Fabian's comment, I changed the logout method to this:
FormsAuthentication.SignOut();
HttpCookie cookie = HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName];
cookie.Expires = DateTime.Now.AddYears(-1);
HttpContext.Current.Response.Cookies.Clear();
HttpContext.Current.Response.Cookies.Add(cookie);
return "home";
Instead of creating a new cookie, I used the one in the response. It did not work.
I also tried something I found from here: http://techblog.dorogin.com/2013/01/formsauthentication-gotcha-with-signout.html That also did no difference, the path was not the problem. Still looking for a solution.
ANOTHER EDIT:
Still not able to find a solution for this. I had to make a horrible workaround.
Login: I make two reloads after the login and then a request to
a dummy method. This seems to work every time.
Logout: I use a flag placed in localStorage to determine if the user has logged out and perform a logout in the startup. This always removes the cookie correctly.
I'm not happy with these hacks and I'm still hoping for a better solution.
PhoneGap loads files from file:// protocol. Unfortunately, cross origin requests are not allowed and unless you open cross origin requests from all hosts *, this problem will not resolve.
There are multiple ways this can be fixed but they are really long.
Load Html from http://
Load entire website from web server instead of local storage. This removes all issues with cross origin requests. Benefit is you don't need to publish new version of app when you change UI. But you will have to implement very powerful caching and first time opening app will take longer time.
Intercept http:// and deliver local files
As you know, phonegap simply uses WebView, in all platforms, you can simply override Url protocol to inject files from your app's local storage. This will be faster, and browser will think that it is loading html from same resource.
Setup OAuth + custom header for authentication
Redirect to a login page hosted at your website say http://domain.com/api/login
After successful login, use PhoneGap localStorage (not browser's localStorage) to store authorization.
Navigate to your local html pages from app and for each json api request you send to server, send authorization header as separate header in ajax request.
Setup a Authorization module, where you can manually authorize asp.net request if your authorization was sent through custom header in http request
I believe I have found the solution. The Phonegap version on your config.xml file is cli-5.1.1, which includes Android Phonegap version 4.0.2 according to the documentation.
The problem with the versions is it seems the Android Phonegap team eventually fixed the cookie storage problem on version 5.2.0. It can be found in release notes as:
CB-10896 We never enabled cookies on the WebView proper
Therefore, updating your Phonegap to latest version should solve the problem.
According to MSDN:
The FormsAuthentication.SignOut method removes the
forms-authentication ticket information from the cookie.
And that's all you need to log the user out. You don't need to expire or remove your cookie itself. Simply change your Logout() to:
[ActionName("logout")]
[AllowAnonymous]
public String Logout()
{
FormsAuthentication.SignOut();
return "home";
}