React Native: Security Of REST API with Firebase
By: Abdullah Liaqat
Tags: React Native, Firebase Admin Sdk, Security, Rest Api, Oauth2

The vulnerability of using Rest API in mobile applications

When the websites in the browser make a call to REST API, the server can identify and respond to the unauthorized calls very easily. There is a security mechanism developed in the HTTP called CORS (Cross-Origin Resource Sharing) policy which is responsible for the identification of any unauthorized access to the resources living in the backend server. This security feature makes sure that the request is coming from a trusted origin only. In other words, any website A cannot have access to the REST API of website B. And it totally makes sense when you have designed your backend to not be available as public API.

But when it comes to a mobile application, there is no way of applying a check on the server just like CORS policy. The problem is very clear here. The websites are accessible to the user via a specific URL and every request is made from that white-listed URL (origin) on behalf of the user. But in the case of a mobile application, a system executable file for a specific platform is distributed to the users. Here comes the vulnerability of this approach. There is no universal method or policy (just like CORS policy) which can come in action and tell the server about the authenticity of the user. In other words, anyone can make the API calls to your server from their cloned version of the application.

// Make requests to Rest API using axios

import axios from 'axios'; export default class App extends React.Component{ componentDidMount(){

axios.get('http://example.com')

.then(res => {

// handle response from request here

})

.catch(err => {

// catch any error here

})

} render(){

return(

// React Native Component

)

}

}

Possible Solutions With Some Limitations

One common approach that can come to our minds is to include an app secret in the application which can ultimately become the part of the header of every API request to the server. It makes sense to follow this approach when the hacker is not very smart. Unfortunately, it is not the case most of the time. A potential hacker can reverse engineer the mechanism of generating such app secrets or even extract it from the source code of the application. It is not a very easy job to mint such app secrets, but it is not impossible either. In other words, anything that is available to the hacker in the form of a system executable file (.apk for android and .ipa for ios) is vulnerable. So, this approach can work sometimes but it is not the best one.

Another approach that can possibly work is to authenticate the user on the client-side by means of JWT and then authenticate every request on the server by passing Token to the server for authentication. But, is this our problem in the first place? The answer is no. Our problem is authorization, not authentication. Even if we authenticate the user on the client-side, there is no way to tell whether the authentication is done on the original application or the hacker’s version of the application.

Similarly, every approach that tries to declare the application as the original version, by adding something in the application that is available to the users, will fail at some point because of the fact the application is also available to the hacker after all.

Solution To Our Problem Using Firebase Auth

Let me explain this approach first. We need to take advantage of the authentication flow Firebase Auth. When we create a project on Firebase and add our app to the project, it requires some unique keys related to the application. For example: In the case of an android application, it requires the Android Package Name and SHA-1 hash of the signing certificate of application.

So, it allows us to make sure that only the users of the registered application are able to get authenticated and pass Firebase ID Token to the server and then Firebase Admin SDK on the server can validate the Token and thus authorize the user accordingly. The best part is that the Token keeps on getting refreshed in regular intervals so there is no need to store the token inside the application. Therefore, the hacker has no way of accessing this ID Token unless the connection between the user and server is compromised.

The id token for an authenticated user can be retrieved very easily using the Firebase Client SDK and the user can request a fresh token from the server any time.

firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {

// Send token to your backend via HTTPS

// ...

}).catch(function(error) {

// Handle error

});

The server side Admin SDK of Firebase can validate the token coming from a specific user.

// idToken comes from the client app

admin.auth().verifyIdToken(idToken)

.then(function(decodedToken) {

let uid = decodedToken.uid;

// ...

}).catch(function(error) {

// Handle error

});

Conclusion

In conclusion, mobile applications can be made secure if potential vulnerabilities are taken into account properly. And it is very important to structure the application security layer in the development phase because it will become costly if the security layer is added to a running production application. The advantage of using a service like Firebase is that there is no need to set up and maintain Auth servers for your application.