We're building an iOS native app together with two web apps. For identiy/access management we are using Keycloak (supports OpenID Connect and OAuth 2.0).
The iOS apps are installed on MDM managed devices. Only our apps are installed.
I learnt that the current best practice for implementing authentication/authorization is to use OpenId Connect and a browser based flow through an external user agent:
http://lists.jboss.org/pipermail/keycloak-dev/2016-May/007259.html
https://www.rfc-editor.org/rfc/rfc8252.txt
https://auth0.com/blog/oauth-2-best-practices-for-native-apps/
using one of these libraries:
https://github.com/openid/AppAuth-iOS
https://github.com/aerogear/aerogear-ios-oauth2
Is it also recommended for MDM managed iOS devices (with no "evil" third party apps, just our own stuff) to implement a browser based flow? Or is it safe in this case to implement a native login flow (user enters credentials directly into the app)?
I am worried about the user experience... That switch between our app and the browser does not look very smooth...
There is an RFC about OAuth2 for native apps. It's worth reading - it discusses possible implementations and security risks involved. The general recommended way is to use the authorization code flow in a browser (not an internal application component), because this way the application cannot get the user credentials. People use to trust the browser and the authentication provider more than other apps, so the visibility of URL and the verified SSL certificate is important too.
The RFC covers also the iOS implementation details:
Apps can initiate an authorization request in the browser, without the
user leaving the app, through the "SFSafariViewController" class or
its successor "SFAuthenticationSession", which implement the in- app
browser tab pattern. Safari can be used to handle requests on old
versions of iOS without in-app browser tab functionality.
So if you use the SFAuthenticationSession you don't need to open a new Safari window and the user experience should not suffer.
If you use the Resource Owner Password Credentials grant (users enter their credentials into your application directly), you will make it less secure for the same reasons - the credentials get exposed to the application. And using this grant, you cannot use the third party authentication providers in Keycloak (Google, Facebook).
It's up to you (and your organization) how much secure you want the system to be, so you can opt for some compromises, but I would rather stick to the current best practices, since the app may grow later the compromises may turn to problems.
Related
For confidential clients, there are scopes assigned to clients and the logged in user has to consent to them. Since there is client secret involved in exchange of auth code for access token, no one can impersonate them and take advantage of their scopes.
But when it comes to pkce flow on a native app, if I had someone else's clientId (clientIds are not considered private information) which has a lot of scopes, I could just start the flow with with their clientId. What is stopping a hacker from using some reputed clientId in the PKCE flow and have access to all their scopes?
NATIVE CALLBACK METHODS
If you look at RFC8252, certain types of callback URL can be registered by more than one app, meaning only a client ID needs to be stolen in order to impersonate a real app, as you say.
This still requires a malicious app to trick the user to sign in before tokens can be retrieved. And of course each app should use only the scopes it needs, and prefer readonly ones. After that it depends on the type of native app.
MOBILE
A mobile app can use Claimed HTTPS Schemes via an https callback URL to overcome this. It is backed by App Links on Android or Universal Links on iOS. Even if a malicious app uses the client ID, it cannot receive the login response with the authorization code, because it will be received on a URL like this, and the mobile OS will only pass this to the app that has proved ownership of the domain via the deep linking rehistration process:
https://mobile.mycompany.com/callback?code=xxx
DESKTOP
For desktop apps there are gaps, since only Loopback and Private URI Scheme callback URLs can be used. It relies on users to avoid installing malicious apps. Eg only install apps from stores that require code signing, which also inform the user who the publisher is. If users install malicious apps then perhaps they have deeper problems.
ATTESTATION
A newer technique is to use a form of client authentication before authentication begins. For confidential clients, Pushed Authorization Requests are used, which uses the app's client credential, so this cannot be used by native clients by default.
Mobile apps could potentially provide proof of ownership of their Google / Apple signing keys during authentication, and there is a proposed standard around that.
i have to develop the backend of a mobile app (IOS swift). I started to create the api with laravel.
But i'm concerned about the access to my api: how i should i give access to my api ? i've heard some stuff about Oauth key and passport .
For my app i want to :
-user can create an account (i guess it's with JWT)
-user can navigate in my app and start to use it after they create their account.
I wan't know the basic process about creating an api for a private use (only my app will use it) what security stuff should i implement and how the account creation for my app will work. Thx :)
PRIVATE APIs
wan't know the basic process about creating an api for a private use (only my app will use it)
Let me tell you here a cruel truth...
No matter if an API doesn't have public accessible documentation or if is is protected by any kind of secret or authentication mechanisms, once is accessible from the internet is not private any-more.
So you can make it hard to find and access, but to truly lock it to your mobile app you will gonna have an hard time to do it so.
WHO AND WHAT IS ACCESSING THE API SERVER
The WHO is the user of the mobile app that you can authenticate,authorize and identify in several ways, like using OpenID or OAUTH2 flows.
Now you need a way to identify WHAT is calling your API server and here things become more tricky than most developers may think. The WHAT is the thing making the request to the API server, is it really your genuine mobile app or is a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
Well to identify the WHAT developers tend to resort to an API key that usually they hard-code in the code of their mobile app and some go the extra mile and compute it at run-time in the mobile app, thus becomes a dynamic secret in opposition to the former approach that is a static secret embedded in the code.
REVERSE ENGINEERING A MOBILE APP BINARY IS EASY
The truth is that anything running in the client side can be reverse engineered
easily by an attacker on a device he controls. He will use introspection frameworks like Frida or xPosed to intercept at runtime the running code of the mobile app or will use a proxy tool like MiTM Proxy for watching the communications between the mobile app and the API server. Normally their first step in reverse engineer a mobile app will be to use the Mobile Security Framework to reverse engineer the binary of you mobile app to extract all static secrets and to identify attack vectors.
Mobile Security Framework
Mobile Security Framework is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing framework capable of performing static analysis, dynamic analysis, malware analysis and web API testing.
Frida
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
xPosed
Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo.
MiTM Proxy
An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.
So now what... Am I doomed to the point I cannot protect my API server from being abused??? No quiet so... hope still exists!!!
A POSSIBLE SOLUTION
So anything that runs on the client side and needs some secret to access an API can be abused in different ways and you can learn more on this series of articles about Mobile API Security Techniques. This articles will teach you how API Keys, User Access Tokens, HMAC and TLS Pinning can be used to protect the API and how they can be bypassed.
But i'm concerned about the access to my api: how i should i give access to my api ? i've heard some stuff about Oauth key and passport .
For my app i want to :
-user can create an account (i guess it's with JWT)
-user can navigate in my app and start to use it after they create their account.
...and how the account creation for my app will work.
Laravel Passport is an OAUTH2 server thus is a good solution to use for user creation and identification, thus to solve the problem of WHO is using your mobile app and API server.
what security stuff should i implement
To solve the problem of WHAT is accessing your mobile app you need to use one or all the solutions mentioned in the series of articles about Mobile API Security Techniques that I mentioned above and accepted that they can only make unauthorized access to your API server harder to bypass but not impossible.
A better solution can be employed by using a Mobile App Attestation solution that will enable the API server to know is receiving only requests from a genuine mobile app.
Mobile App Attestation
Use a Mobile App Attestation solution to enable the API server to know WHAT is sending the requests, thus enabling it to only respond to requests from a genuine mobile app.
The role of a Mobile App Attestation service is to guarantee at run-time that your mobile app was not tampered or is not running in a rooted device by running a SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device is running on.
On successful attestation of the mobile app integrity a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud are aware. In the case of failure on the mobile app attestation the JWT token is signed with a secret that the API server does not know.
Now the App must sent with every API call the JWT token in the headers of the request. This will allow the API server to only serve requests when it can verify the signature and expiration time in the JWT token and refuse them when it fails the verification.
Once the secret used by the Mobile App Attestation service is not known by the mobile app, is not possible to reverse engineer it at run-time even when the App is tampered, running in a rooted device or communicating over a connection that is being the target of a Man in the Middle Attack.
The Mobile App Attestation service already exists as a SAAS solution at Approov(I work here) that provides SDKs for several platforms, including iOS, Android, React Native and others. The integration will also need a small check in the API server code to verify the JWT token issued by the cloud service. This check is necessary for the API server to be able to decide what requests to serve and what ones to deny.
Currently in the process of moving from OAuth1 to OAuth2 in a desktop application for a web service (Imgur), I've been baffled by the OAuth2 specs. Apparently it breaks all the security OAuth1 provided, according to this doc http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified and by looking at different services docs regarding OAuth2.
With OAuth1 you could use a URL to the service where the user would grant access and a PIN was displayed to copy/paste in your app, which was really nice security in the sense that the user never grants their login/password to the app, and can revoke the given access to it at any time through the service's website.
Now with OAuth2 they left this scenario out, forcing the app to request the user's login/password, unless the app makes their own script in their website to receive a token from the service after granting access (then have the user copy/paste it from your website)
Am I missing something here?
Desktop applications can and should use a user agent (browser) to do OAuth and that is described in the OAuth 2 spec under "Native Applications". The flow you described is meant more for devices with limited input capabilities like a gaming console, printer, camera, etc.
AFAIK, the device flow was in the early specs of OAuth 2, but was omitted at some point. Some API providers like Google have implemented limited support for it regardless.
Native applications are the way to go. See the ["Native Applications"][1] section of OAuth 2.0 RFC. The native applications are not intended to store passwords. If you want to avoid entering of credentials directly in the app (even within a browser control), you may do the following from the OAuth 2.0 native application:
Launch the default browser with the authorization endpoint.
Implement a simple web page for your redirect URI, which picks the authorization code and shows it to the user.
Ask the user to copy the code and paste it back in the native application.
Alternatively, the spec suggests that you leverage the URL redirection scheme of the native platform to bring back the original application. You may check iOS and Android's "URL Scheme" capabilities. Unfortunately, neither of these platforms guarantees uniqueness of the URL scheme, hence the authorization code may be hijacked by another rogue app, which is activated on the same URL. I have filed an iOS bug for that.
[1]: https://www.rfc-editor.org/rfc/rfc6749#page-52
Is it possible to make oauth secure on iOS?
I am investigating OAuth 2.0 as a means to implement single sign-on + authorization for a "suite" of iOS apps. To explain my concerns, I'll simplify and use Facebook + a 3rd party app that uses Facebook for authentication (let's say Words/"Words with Friends").
For the purpose of example, I'll assume that Facebook registers to support scheme/protocol "facebook://" and that Words registers to support "words://"
I also make the assumption that it is not possible to secure the "client-secret" or the protocol in an iOS application because you can decompile the application. Any ways that I have come up with to secure this results in security by obscurity.
Another assumption is that there is no way to prevent two applications from registering to handle the same protocol. The behavior when two apps both register for the same protocol is indeterminate. (Although it appears that the first app to launch on the device gets registered while the second apps registration is ignored)
If I understand the workflow between Facebook (user-agent) and Words (client) on the iOS device:
User launches Words
user chooses to logon via Facebook credentials
Words invokes openUrl("facebook://") which contains, among other things an identifier for Words as an application and a redirect uri (i.e. "words://")
iOS launches Facebook application
User enteres credentials, which Facebook application validates against Facebook authorization server.
User prompted to authorize Words to access Facebook data (i.e. Words can access my friends list)
Facebook invokes callback uri provided by Words along with access token (i.e. words://access_token?token_here)
Words uses this token to access my friends list (i.e. protected resource data)
Assuming the above is correct, if I want to be malicious and access random people's friends list, I could create an application that also registers to handle the protocol "words://" and get it on the app store. If someone has my app and Words installed and my app is the one that successfully registered (i.e. launched on the device before Words), then:
Launch Words, choose to logon, launches Facebook
user authenticates / authorizes
Facebook attempts to redirect back to Words by invoking openUrl on the redirect url
My App (not Words) is launched
My App now has access to the auth code, which (with the secret learned by decompiling) can be exchanged for an access_token, with rights to access your friends list
I am hoping that my reasoning is flawed above or I would have to conclude (specifically) that Facebook iOS authentication for 3rd party apps is insecure.
More generically, is it possible to implement OAuth 2.0 (authorization/implicit grant workflows) securely on iOS application?
Google has come up with an experimental solution for this problem that they call OAuth 2.0 for Installed Applications.
The Google OAuth 2.0 endpoint supports applications that are installed on a device...it is assumed that these applications cannot keep secrets.
Essentially, the shared secret is treated as non-secret.
At the time of this writing, most OAuth 2.0 servers do not seem to support this experimental design.
This design introduces the risk that an attacker could create a new client that represents itself as your application to the authorization server (the attacker would need to obtain the client identifier as you describe in your question, or by following one of the techniques suggested here).
However, this risk seems to be mitigated by the fact that the resource owner (the user) would be unlikely to authorize the malicious application to take any action on protected resources, since he/she will know that the application is not, in fact, your application.
As we all know social networks like Twitter, Facebook have their own mobile apps. Other 3rd party apps use their API which can be authenticated over only OAuth protocol after registering for an app.
So how exactly do Facebook, Twitter, Foursquare etc. access their API on their own mobile apps via authenticating by "username" and "password"? I don't think that they just send username and password as parameter on each request.
One more important point is, when you log in those official mobile apps, you don't come across a web interface, asking for permission and has button "Allow this app" which exists in OAuth process. They're authenticated by default!
While investigating I came across XAuth, however after watching its introductory video, it seemed like a shared storage on browser. I'm not looking for that and then I came across use of xAuth in Twitter. It authenticates by sending username/password once over SSL and then server issues an OAuth token/secret pair. (This looks like OAuth v1 instead of v2, which is not cool.)
It looks like what I'm looking for but I'm not quite sure. Are there any alternatives other than maintaining an OAuth server that xAuth requires? Because in my use case, probably 3rd party apps will not exist at all.
In cases like these, the official apps just use whatever authentication they want. I think the point of using OAuth and XAuth for non-official applications are to allow some access to those 3rd parties that (1) can be revoked by the user, and (2) don't require the 3rd party to have the username/password of the user themselves. In fact, before more widespread adoption of OAuth, et al., 3rd party apps requiring your username and password were very common. It was only after Facebook turned off this kind of access, that the OAuth method became more commonly used (in their case).
In the case of the official apps, there's no reason to go through OAuth, because in order to get an OAuth authentication token, you have to enter your username and password anyway. In the case of the official apps, that would make this redundant, and unnecessary.
The official apps could also be speaking to a dedicated set of authentication servers that only accept logins from the mobile app, the mobile app might be providing some special, extra information that identifies it as the official app, or some other mechanism on top of username and password for authentication. I'm not a Facebook developer, so I don't know. But my point is, Facebook/Twitter probably have a separate API password-based logins, and that API is only accessible by the web interface, and other official modes of login.
So, in your case, if you're building a social network (or any web service that will have mobile access) simply use the standard password-based login for your official app, but don't make that login method available to everyone. If you want to allow for 3rd party access through an API, you will really need to setup an OAuth/XAuth server to do this, in terms of keeping your users' passwords only under your control (and not leaked out to 3rd party groups/sites/apps).