Files
react-native/docs/security.html
T
2021-02-01 14:39:14 +00:00

45 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-alpha.66">
<link rel="alternate" type="application/rss+xml" href="/blog/rss.xml" title="React Native Blog RSS Feed">
<link rel="alternate" type="application/atom+xml" href="/blog/atom.xml" title="React Native Blog Atom Feed">
<link rel="preconnect" href="https://www.google-analytics.com">
<script>window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)},ga.l=+new Date,ga("create","UA-41298772-2","auto"),ga("send","pageview")</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
<link rel="preconnect" href="https://www.google-analytics.com">
<link rel="preconnect" href="https://www.googletagmanager.com">
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-41298772-2"></script>
<script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","UA-41298772-2",{})</script>
<link rel="search" type="application/opensearchdescription+xml" title="React Native" href="/opensearch.xml">
<script src="https://cdn.jsdelivr.net/npm/focus-visible@5.2.0/dist/focus-visible.min.js" defer="defer"></script>
<script src="https://snack.expo.io/embed.js" defer="defer"></script><title data-react-helmet="true">Security · React Native</title><meta data-react-helmet="true" property="twitter:image" content="https://reactnative.dev/img/logo-og.png"><meta data-react-helmet="true" name="twitter:image:alt" content="Image for React Native"><meta data-react-helmet="true" name="docsearch:language" content="en"><meta data-react-helmet="true" name="docsearch:version" content="0.63"><meta data-react-helmet="true" name="docsearch:docusaurus_tag" content="docs-default-0.63"><meta data-react-helmet="true" property="og:image" content="https://reactnative.dev/img/logo-og.png"><meta data-react-helmet="true" name="twitter:card" content="summary"><meta data-react-helmet="true" name="twitter:image" content="https://reactnative.dev/img/logo-og.png"><meta data-react-helmet="true" property="og:title" content="Security · React Native"><meta data-react-helmet="true" name="description" content="Security is often overlooked when building apps. It is true that it is impossible to build software that is completely impenetrable—weve yet to invent a completely impenetrable lock (bank vaults do, after all, still get broken into). However, the probability of falling victim to a malicious attack or being exposed for a security vulnerability is inversely proportional to the effort youre willing to put in to protecting your application against any such eventuality. Although an ordinary padlock is pickable, it is still much harder to get past than a cabinet hook!"><meta data-react-helmet="true" property="og:description" content="Security is often overlooked when building apps. It is true that it is impossible to build software that is completely impenetrable—weve yet to invent a completely impenetrable lock (bank vaults do, after all, still get broken into). However, the probability of falling victim to a malicious attack or being exposed for a security vulnerability is inversely proportional to the effort youre willing to put in to protecting your application against any such eventuality. Although an ordinary padlock is pickable, it is still much harder to get past than a cabinet hook!"><meta data-react-helmet="true" property="og:url" content="https://reactnative.dev/docs/security"><link data-react-helmet="true" rel="shortcut icon" href="/img/favicon.ico"><link data-react-helmet="true" rel="preconnect" href="https://BH4D9OD16A-dsn.algolia.net" crossorigin="anonymous"><link data-react-helmet="true" rel="canonical" href="https://reactnative.dev/docs/security"><link rel="stylesheet" href="/styles.fccefeba.css">
<link rel="stylesheet" href="/main.ca40cabd.css">
<link rel="preload" href="/styles.07d522c6.js" as="script">
<link rel="preload" href="/runtime~main.579b1f59.js" as="script">
<link rel="preload" href="/main.5e05a427.js" as="script">
<link rel="preload" href="/1.ba9ce8bd.js" as="script">
<link rel="preload" href="/2.58cb5d3d.js" as="script">
<link rel="preload" href="/1f391b9e.a824c215.js" as="script">
<link rel="preload" href="/943.8b024446.js" as="script">
<link rel="preload" href="/ee5b3385.b4fff665.js" as="script">
<link rel="preload" href="/17896441.0c201679.js" as="script">
<link rel="preload" href="/d842fc1f.b11c5056.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<nav class="navbar navbar--fixed-top navbar--dark"><div class="navbar__inner"><div class="navbar__items"><div aria-label="Navigation bar toggle" class="navbar__toggle" role="button" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></div><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/header_logo.svg" alt="React Native"><strong class="navbar__title">React Native</strong></a><div class="navbar__item dropdown dropdown--hoverable dropdown--left"><a class="navbar__item navbar__link" href="/docs/getting-started">0.63</a><ul class="dropdown__menu"><li><a class="dropdown__link" href="/docs/next/security">Next</a></li><li><a aria-current="page" class="dropdown__link dropdown__link--active" href="/docs/security">0.63</a></li><li><a class="dropdown__link" href="/docs/0.62/security">0.62</a></li><li><a class="dropdown__link" href="/docs/0.61/getting-started">0.61</a></li><li><a class="dropdown__link" href="/docs/0.60/getting-started">0.60</a></li><li><a class="dropdown__link" href="/versions">All versions</a></li></ul></div></div><div class="navbar__items navbar__items--right"><a class="navbar__item navbar__link navbar__link--active" href="/docs/getting-started">Docs</a><a class="navbar__item navbar__link" href="/docs/components-and-apis">Components</a><a class="navbar__item navbar__link" href="/docs/accessibilityinfo">API</a><a class="navbar__item navbar__link" href="/help">Community</a><a class="navbar__item navbar__link" href="/blog">Blog</a><a href="https://github.com/facebook/react-native" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link navbar-github-link" aria-label="GitHub repository"></a><div class="react-toggle react-toggle--disabled displayOnlyInLargeViewport_3lWe"><div class="react-toggle-track"><div class="react-toggle-track-check"><span class="toggle_gnXW">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_gnXW">🌞</span></div></div><div class="react-toggle-thumb"></div><input type="checkbox" disabled="" aria-label="Dark mode toggle" class="react-toggle-screenreader-only"></div><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span><span class="DocSearch-Button-Key"></span><span class="DocSearch-Button-Key">K</span></button></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div><div class="navbar-sidebar"><div class="navbar-sidebar__brand"><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/header_logo.svg" alt="React Native"><strong class="navbar__title">React Native</strong></a></div><div class="navbar-sidebar__items"><div class="menu"><ul class="menu__list"><li class="menu__list-item"><a class="menu__link navbar__link--active" href="/docs/getting-started">Docs</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/components-and-apis">Components</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/accessibilityinfo">API</a></li><li class="menu__list-item"><a class="menu__link" href="/help">Community</a></li><li class="menu__list-item"><a class="menu__link" href="/blog">Blog</a></li><li class="menu__list-item"><a role="button" class="menu__link menu__link--sublist">Versions</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" href="/docs/next/security">Next</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active" href="/docs/security">0.63</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/0.62/security">0.62</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/0.61/getting-started">0.61</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/0.60/getting-started">0.60</a></li><li class="menu__list-item"><a class="menu__link" href="/versions">All versions</a></li></ul></li><li class="menu__list-item"><a href="https://github.com/facebook/react-native" target="_blank" rel="noopener noreferrer" class="menu__link navbar-github-link" aria-label="GitHub repository"></a></li></ul></div></div></div></nav><div class="main-wrapper"><div class="docPage_2UBv"><div class="docSidebarContainer_1hqR" role="complementary"><div class="sidebar_MSwm"><div class="menu menu--responsive menu_2hiu"><button aria-label="Open Menu" aria-haspopup="true" class="button button--secondary button--sm menu__button" type="button"><svg aria-label="Menu" class="sidebarMenuIcon_37TU" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 32 32" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><ul class="menu__list"><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">The Basics</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/getting-started">Introduction</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/intro-react-native-components">Core Components and Native Components</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/intro-react">React Fundamentals</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/handling-text-input">Handling Text Input</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/using-a-scrollview">Using a ScrollView</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/using-a-listview">Using List Views</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/troubleshooting">Troubleshooting</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/platform-specific-code">Platform Specific Code</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/more-resources">More Resources</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Environment setup</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/environment-setup">Setting up the development environment</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/integration-with-existing-apps">Integration with Existing Apps</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/building-for-tv">Building For TV Devices</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/out-of-tree-platforms">Out-of-Tree Platforms</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Workflow</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/running-on-device">Running On Device</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/fast-refresh">Fast Refresh</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/debugging">Debugging</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/testing-overview">Testing</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/libraries">Using Libraries</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/typescript">Using TypeScript</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/upgrading">Upgrading to new React Native versions</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Design</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/style">Style</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/height-and-width">Height and Width</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/flexbox">Layout with Flexbox</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/images">Images</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/colors">Color Reference</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Interaction</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/handling-touches">Handling Touches</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/navigation">Navigating Between Screens</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/animations">Animations</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/gesture-responder-system">Gesture Responder System</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Inclusion</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/accessibility">Accessibility</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Performance</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/performance">Performance Overview</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/optimizing-flatlist-configuration">Optimizing Flatlist Configuration</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/ram-bundles-inline-requires">RAM Bundles and Inline Requires</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/profiling">Profiling</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">JavaScript Runtime</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/javascript-environment">JavaScript Environment</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/timers">Timers</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/hermes">Using Hermes</a></li></ul></li><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#!">Connectivity</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/docs/network">Networking</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active active" tabindex="0" href="/docs/security">Security</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Native Modules</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/native-modules-intro">Native Modules Intro</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/native-modules-android">Android Native Modules</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/native-modules-ios">iOS Native Modules</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/native-modules-setup">Native Modules NPM Package Setup</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Native Components</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/native-components-android">Android Native UI Components</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/native-components-ios">iOS Native UI Components</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/direct-manipulation">Direct Manipulation</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Guides (Android)</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/headless-js-android">Headless JS</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/signed-apk-android">Publishing to Google Play Store</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/removing-default-permissions">Removing Default Permissions</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">Guides (iOS)</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/linking-libraries-ios">Linking Libraries</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/running-on-simulator-ios">Running On Simulator</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/communication-ios">Communication between native and React Native</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/app-extensions">App Extensions</a></li></ul></li></ul></div></div></div><main class="docMainContainer_1rYT"><div class="container padding-vert--lg docItemWrapper_1Hme"><div class="row"><div class="col docItemCol_2AGf"><div class="docItemContainer_1tAC"><article><header><h1 class="docTitle_cWlf">Security</h1></header><div class="markdown"><p>Security is often overlooked when building apps. It is true that it is impossible to build software that is completely impenetrable—weve yet to invent a completely impenetrable lock (bank vaults do, after all, still get broken into). However, the probability of falling victim to a malicious attack or being exposed for a security vulnerability is inversely proportional to the effort youre willing to put in to protecting your application against any such eventuality. Although an ordinary padlock is pickable, it is still much harder to get past than a cabinet hook!</p><img src="/docs/assets/d_security_chart.svg" width="283" alt=" " style="float:right"><p>In this guide, you will learn about best practices for storing sensitive information, authentication, network security, and tools that will help you secure your app. This is not a preflight checklist—it is a catalogue of options, each of which will help further protect your app and users.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="storing-sensitive-info"></a>Storing Sensitive Info<a aria-hidden="true" tabindex="-1" class="hash-link" href="#storing-sensitive-info" title="Direct link to heading">#</a></h2><p>Never store sensitive API keys in your app code. Anything included in your code could be accessed in plain text by anyone inspecting the app bundle. Tools like <a href="https://github.com/goatandsheep/react-native-dotenv" target="_blank" rel="noopener noreferrer">react-native-dotenv</a> and <a href="https://github.com/luggit/react-native-config/" target="_blank" rel="noopener noreferrer">react-native-config</a> are great for adding environment-specific variables like API endpoints, but they should not be confused with server-side environment variables, which can often contain secrets and API keys.</p><p>If you must have an API key or a secret to access some resource from your app, the most secure way to handle this would be to build an orchestration layer between your app and the resource. This could be a serverless function (e.g. using AWS Lambda or Google Cloud Functions) which can forward the request with the required API key or secret. Secrets in server side code cannot be accessed by the API consumers the same way secrets in your app code can.</p><p><strong>For persisted user data, choose the right type of storage based on its sensitivity.</strong> As your app is used, youll often find the need to save data on the device, whether to support your app being used offline, cut down on network requests or save your users access token between sessions so they wouldnt have to re-authenticate each time they use the app.</p><blockquote><p><strong>Persisted vs unpersisted</strong> — persisted data is written to the devices memory, which lets the data be read by your app across application launches without having to do another network request to fetch it or asking the user to re-enter it. But this also can make that data more vulnerable to being accessed by attackers. Unpersisted data is never written to memory—so there&#x27;s no data to access!</p></blockquote><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="async-storage"></a>Async Storage<a aria-hidden="true" tabindex="-1" class="hash-link" href="#async-storage" title="Direct link to heading">#</a></h3><p><a href="https://github.com/react-native-community/async-storage" target="_blank" rel="noopener noreferrer">Async Storage</a> is a community-maintained module for React Native that provides an asynchronous, unencrypted, key-value store. Async Storage is not shared between apps: every app has its own sandbox environment and has no access to data from other apps.</p><table><thead><tr><th><strong>Do</strong> use async storage when...</th><th><strong>Don&#x27;t</strong> use async storage for...</th></tr></thead><tbody><tr><td>Persisting non-sensitive data across app runs</td><td>Token storage</td></tr><tr><td>Persisting Redux state</td><td>Secrets</td></tr><tr><td>Persisting GraphQL state</td><td></td></tr><tr><td>Storing global app-wide variables</td><td></td></tr></tbody></table><h4><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="developer-notes"></a>Developer Notes<a aria-hidden="true" tabindex="-1" class="hash-link" href="#developer-notes" title="Direct link to heading">#</a></h4><div><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_3gSF tabs__item--active" style="outline:none">Web</li></ul><div role="tabpanel" class="margin-vert--md"><div><blockquote><p>Async Storage is the React Native equivalent of Local Storage from the web</p></blockquote></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="secure-storage"></a>Secure Storage<a aria-hidden="true" tabindex="-1" class="hash-link" href="#secure-storage" title="Direct link to heading">#</a></h3><p>React Native does not come bundled with any way of storing sensitive data. However, there are pre-existing solutions for Android and iOS platforms.</p><h4><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="ios---keychain-services"></a>iOS - Keychain Services<a aria-hidden="true" tabindex="-1" class="hash-link" href="#ios---keychain-services" title="Direct link to heading">#</a></h4><p><a href="https://developer.apple.com/documentation/security/keychain_services" target="_blank" rel="noopener noreferrer">Keychain Services</a> allows you to securely store small chunks of sensitive info for the user. This is an ideal place to store certificates, tokens, passwords, and any other sensitive information that doesnt belong in Async Storage.</p><h4><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="android---secure-shared-preferences"></a>Android - Secure Shared Preferences<a aria-hidden="true" tabindex="-1" class="hash-link" href="#android---secure-shared-preferences" title="Direct link to heading">#</a></h4><p><a href="https://developer.android.com/reference/android/content/SharedPreferences" target="_blank" rel="noopener noreferrer">Shared Preferences</a> is the Android equivalent for a persistent key-value data store. <strong>Data in Shared Preferences is not encrypted by default</strong>, but <a href="https://developer.android.com/topic/security/data" target="_blank" rel="noopener noreferrer">Encrypted Shared Preferences</a> wraps the Shared Preferences class for Android, and automatically encrypts keys and values.</p><h4><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="android---keystore"></a>Android - Keystore<a aria-hidden="true" tabindex="-1" class="hash-link" href="#android---keystore" title="Direct link to heading">#</a></h4><p>The <a href="https://developer.android.com/training/articles/keystore" target="_blank" rel="noopener noreferrer">Android Keystore</a> system lets you store cryptographic keys in a container to make it more difficult to extract from the device.</p><p>In order to use iOS Keychain services or Android Secure Shared Preferences, you can either write a bridge yourself or use a library which wraps them for you and provides a unified API at your own risk. Some libraries to consider:</p><ul><li><a href="https://docs.expo.io/versions/latest/sdk/securestore/" target="_blank" rel="noopener noreferrer">expo-secure-store</a></li><li><a href="https://github.com/emeraldsanto/react-native-encrypted-storage" target="_blank" rel="noopener noreferrer">react-native-encrypted-storage</a> - uses Keychain on iOS and EncryptedSharedPreferences on Android.</li><li><a href="https://github.com/oblador/react-native-keychain" target="_blank" rel="noopener noreferrer">react-native-keychain</a></li><li><a href="https://github.com/mCodex/react-native-sensitive-info" target="_blank" rel="noopener noreferrer">react-native-sensitive-info</a> - secure for iOS, but uses Android Shared Preferences for Android (which is not secure by default). There is however a <a href="https://github.com/mCodex/react-native-sensitive-info/tree/keystore" target="_blank" rel="noopener noreferrer">branch</a> that uses Android Keystore.<ul><li><a href="https://github.com/CodingZeal/redux-persist-sensitive-storage" target="_blank" rel="noopener noreferrer">redux-persist-sensitive-storage</a> - wraps react-native-sensitive-info for Redux.</li></ul></li></ul><blockquote><p><strong>Be mindful of unintentionally storing or exposing sensitive info.</strong> This could happen accidentally, for example saving sensitive form data in redux state and persisting the whole state tree in Async Storage. Or sending user tokens and personal info to an application monitoring service such as Sentry or Crashlytics.</p></blockquote><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="authentication-and-deep-linking"></a>Authentication and Deep Linking<a aria-hidden="true" tabindex="-1" class="hash-link" href="#authentication-and-deep-linking" title="Direct link to heading">#</a></h2><img src="/docs/assets/d_security_deep-linking.svg" width="225" alt=" " style="float:right;margin:0 0 1em 1em"><p>Mobile apps have a unique vulnerability that is non-existent in the web: <strong>deep linking</strong>. Deep linking is a way of sending data directly to a native application from an outside source. A deep link looks like <code>app://</code> where <code>app</code> is your app scheme and anything following the // could be used internally to handle the request.</p><p>For example, if you were building an ecommerce app, you could use <code>app://products/1</code> to deep link to your app and open the product detail page for a product with id 1. You can think of these kind of like URLs on the web, but with one crucial distinction:</p><p>Deep links are not secure and you should never send any sensitive information in them.</p><p>The reason deep links are not secure is because there is no centralized method of registering URL schemes. As an application developer, you can use almost any url scheme you choose by <a href="https://developer.apple.com/documentation/uikit/inter-process_communication/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app" target="_blank" rel="noopener noreferrer">configuring it in Xcode</a> for iOS or <a href="https://developer.android.com/training/app-links/deep-linking" target="_blank" rel="noopener noreferrer">adding an intent on Android</a>.</p><p>There is nothing stopping a malicious application from hijacking your deep link by also registering to the same scheme and then obtaining access to the data your link contains. Sending something like <code>app://products/1</code> is not harmful, but sending tokens is a security concern.</p><p>When the operating system has two or more applications to choose from when opening a link, Android will show the user a modal and ask them to choose which application to use to open the link. On iOS however, the operating system will make the choice for you, so the user will be blissfully unaware. Apple has made steps to address this issue in later iOS versions (iOS 11) where they instituted a first-come-first-served principle, although this vulnerability could still be exploited in different ways which you can read more about <a href="https://blog.trendmicro.com/trendlabs-security-intelligence/ios-url-scheme-susceptible-to-hijacking/" target="_blank" rel="noopener noreferrer">here</a>. Using <a href="https://developer.apple.com/ios/universal-links/" target="_blank" rel="noopener noreferrer">universal links</a> will allow linking to content within your app securely in iOS.</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="oauth2-and-redirects"></a>OAuth2 and Redirects<a aria-hidden="true" tabindex="-1" class="hash-link" href="#oauth2-and-redirects" title="Direct link to heading">#</a></h3><p>The OAuth2 authentication protocol is incredibly popular nowadays, prided as the most complete and secure protocol around. The OpenID Connect protocol is also based on this. In OAuth2, the user is asked to authenticate via a third party. On successful completion, this third party redirects back to the requesting application with a verification code which can be exchanged for a JWT — a <a href="https://jwt.io/introduction/" target="_blank" rel="noopener noreferrer">JSON Web Token</a>. JWT is an open standard for securely transmitting information between parties on the web.</p><p>On the web, this redirect step is secure, because URLs on the web are guaranteed to be unique. This is not true for apps because, as mentioned earlier, there is no centralized method of registering URL schemes! In order to address this security concern, an additional check must be added in the form of PKCE.</p><p><a href="https://oauth.net/2/pkce/" target="_blank" rel="noopener noreferrer">PKCE</a>, pronounced “Pixy” stands for Proof of Key Code Exchange, and is an extension to the OAuth 2 spec. This involves adding an additional layer of security which verifies that the authentication and token exchange requests come from the same client. PKCE uses the <a href="https://www.movable-type.co.uk/scripts/sha256.html" target="_blank" rel="noopener noreferrer">SHA 256</a> Cryptographic Hash Algorithm. SHA 256 creates a unique “signature” for a text or file of any size, but it is:</p><ul><li>Always the same length regardless of the input file</li><li>Guaranteed to always produce the same result for the same input</li><li>One way (that is, you cant reverse engineer it to reveal the original input)</li></ul><p>Now you have two values:</p><ul><li><strong>code_verifier</strong> - a large random string generated by the client</li><li><strong>code_challenge</strong> - the SHA 256 of the code_verifier</li></ul><p>During the initial <code>/authorize</code> request, the client also sends the <code>code_challenge</code> for the <code>code_verifier</code> it keeps in memory. After the authorize request has returned correctly, the client also sends the <code>code_verifier</code> that was used to generate the <code>code_challenge</code>. The IDP will then calculate the <code>code_challenge</code>, see if it matches what was set on the very first <code>/authorize</code> request, and only send the access token if the values match.</p><p>This guarantees that only the application that triggered the initial authorization flow would be able to successfully exchange the verification code for a JWT. So even if a malicious application gets access to the verification code, it will be useless on its own. To see this in action, check out <a href="https://aaronparecki.com/oauth-2-simplified/#mobile-apps" target="_blank" rel="noopener noreferrer">this example</a>.</p><p>A library to consider for native OAuth is <a href="https://github.com/FormidableLabs/react-native-app-auth" target="_blank" rel="noopener noreferrer">react-native-app-auth</a>. React-native-app-auth is an SDK for communicating with OAuth2 providers. It wraps the native <a href="https://github.com/openid/AppAuth-iOS" target="_blank" rel="noopener noreferrer">AppAuth-iOS</a> and <a href="https://github.com/openid/AppAuth-Android" target="_blank" rel="noopener noreferrer">AppAuth-Android</a> libraries and can support PKCE.</p><blockquote><p>React-native-app-auth can support PKCE only if your Identity Provider supports it.</p></blockquote><p><img alt="OAuth2 with PKCE" src="/assets/images/diagram_pkce-e0b4a829176ac05d07b0bcec73994985.svg"></p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="network-security"></a>Network Security<a aria-hidden="true" tabindex="-1" class="hash-link" href="#network-security" title="Direct link to heading">#</a></h2><p>Your APIs should always use <a href="https://www.ssl.com/faqs/faq-what-is-ssl/" target="_blank" rel="noopener noreferrer">SSL encryption</a>. SSL encryption protects against the requested data being read in plain text between when it leaves the server and before it reaches the client. Youll know the endpoint is secure, because it starts with <code>https://</code> instead of <code>http://</code>.</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="ssl-pinning"></a>SSL Pinning<a aria-hidden="true" tabindex="-1" class="hash-link" href="#ssl-pinning" title="Direct link to heading">#</a></h3><p>Using https endpoints could still leave your data vulnerable to interception. With https, the client will only trust the server if it can provide a valid certificate that is signed by a trusted Certificate Authority that is pre-installed on the client. An attacker could take advantage of this by installing a malicious root CA certificate to the users device, so the client would trust all certificates that are signed by the attacker. Thus, relying on certificates alone could still leave you vulnerable to a <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack" target="_blank" rel="noopener noreferrer">man-in-the-middle attack</a>.</p><p><strong>SSL pinning</strong> is a technique that can be used on the client side to avoid this attack. It works by embedding (or pinning) a list of trusted certificates to the client during development, so that only the requests signed with one of the trusted certificates will be accepted, and any self-signed certificates will not be.</p><blockquote><p>When using SSL pinning, you should be mindful of certificate expiry. Certificates expire every 1-2 years and when one does, itll need to be updated in the app as well as on the server. As soon as the certificate on the server has been updated, any apps with the old certificate embedded in them will cease to work.</p></blockquote><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_3pqN" id="summary"></a>Summary<a aria-hidden="true" tabindex="-1" class="hash-link" href="#summary" title="Direct link to heading">#</a></h2><p>There is no bulletproof way to handle security, but with conscious effort and diligence, it is possible to significantly reduce the likelihood of a security breach in your application. Invest in security proportional to the sensitivity of the data stored in your application, the number of users, and the damage a hacker could do when gaining access to their account. And remember: its significantly harder to access information that was never requested in the first place.</p></div></article><div class="docMetadata margin-vert--xl"><div class="row"><div class="col"><a href="https://github.com/facebook/react-native-website/blob/master/website/versioned_docs/version-0.63/security.md" target="_blank" rel="noreferrer noopener"><svg fill="currentColor" height="1.2em" width="1.2em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 40 40" style="margin-right:0.3em;vertical-align:sub"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col text--right"><em><small class="docMetadata-updated">Last updated on <time datetime="2021-02-01T10:04:24.000Z" class="docLastUpdatedAt_1gIo">2/1/2021</time></small></em></div></div></div><div class="margin-vert--lg"><nav class="pagination-nav" aria-label="Blog list page navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/docs/network"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« Networking</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/docs/native-modules-intro"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Native Modules Intro »</div></a></div></nav></div></div></div><div class="col col--3"><div class="tableOfContents_3iuQ"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#storing-sensitive-info" class="table-of-contents__link">Storing Sensitive Info</a><ul><li><a href="#async-storage" class="table-of-contents__link">Async Storage</a></li><li><a href="#secure-storage" class="table-of-contents__link">Secure Storage</a></li></ul></li><li><a href="#authentication-and-deep-linking" class="table-of-contents__link">Authentication and Deep Linking</a><ul><li><a href="#oauth2-and-redirects" class="table-of-contents__link">OAuth2 and Redirects</a></li></ul></li><li><a href="#network-security" class="table-of-contents__link">Network Security</a><ul><li><a href="#ssl-pinning" class="table-of-contents__link">SSL Pinning</a></li></ul></li><li><a href="#summary" class="table-of-contents__link">Summary</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links"><div class="col footer__col"><h4 class="footer__title">Docs</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs/getting-started">Getting Started</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/tutorial">Tutorial</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/components-and-apis">Components and APIs</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/more-resources">More Resources</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">Community</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/help">The React Native Community</a></li><li class="footer__item"><a class="footer__link-item" href="/showcase">Who&#x27;s using React Native?</a></li><li class="footer__item"><a href="https://stackoverflow.com/questions/tagged/react-native" target="_blank" rel="noopener noreferrer" class="footer__link-item">Ask Questions on Stack Overflow</a></li><li class="footer__item"><a href="https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer" class="footer__link-item">Contributor Guide</a></li><li class="footer__item"><a href="https://dev.to/t/reactnative" target="_blank" rel="noopener noreferrer" class="footer__link-item">DEV Community</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">Find us</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">Blog</a></li><li class="footer__item"><a href="https://twitter.com/reactnative" target="_blank" rel="noopener noreferrer" class="footer__link-item">Twitter</a></li><li class="footer__item"><a href="https://github.com/facebook/react-native" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">More</h4><ul class="footer__items"><li class="footer__item"><a href="https://reactjs.org/" target="_blank" rel="noopener noreferrer" class="footer__link-item">React</a></li><li class="footer__item"><a href="https://opensource.facebook.com/legal/privacy" target="_blank" rel="noopener noreferrer" class="footer__link-item">Privacy Policy</a></li><li class="footer__item"><a href="https://opensource.facebook.com/legal/terms" target="_blank" rel="noopener noreferrer" class="footer__link-item">Terms of Service</a></li></ul></div></div><div class="text--center"><div class="margin-bottom--sm"><a href="https://opensource.facebook.com" target="_blank" rel="noopener noreferrer" class="footerLogoLink_19Ac"><img class="footer__logo" alt="Facebook Open Source Logo" src="/img/oss_logo.png"></a></div><div>Copyright © 2021 Facebook, Inc.</div></div></div></footer></div>
<script src="/styles.07d522c6.js"></script>
<script src="/runtime~main.579b1f59.js"></script>
<script src="/main.5e05a427.js"></script>
<script src="/1.ba9ce8bd.js"></script>
<script src="/2.58cb5d3d.js"></script>
<script src="/1f391b9e.a824c215.js"></script>
<script src="/943.8b024446.js"></script>
<script src="/ee5b3385.b4fff665.js"></script>
<script src="/17896441.0c201679.js"></script>
<script src="/d842fc1f.b11c5056.js"></script>
</body>
</html>