xref: /aosp_15_r20/external/grpc-grpc-java/SECURITY.md (revision e07d83d3ffcef9ecfc9f7f475418ec639ff0e5fe)
1# Security Policy
2
3For information on gRPC Security Policy and reporting potentional security
4issues, please see [gRPC CVE Process][].
5
6[gRPC CVE Process]: https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md
7
8# Authentication
9
10gRPC supports a number of different mechanisms for asserting identity between an
11client and server. This document provides code samples demonstrating how to
12provide SSL/TLS encryption support and identity assertions in Java, as well as
13passing OAuth2 tokens to services that support it.
14
15# Transport Security (TLS)
16
17HTTP/2 over TLS mandates the use of [ALPN](https://tools.ietf.org/html/rfc7301)
18to negotiate the use of the h2 protocol and support for the GCM mode of AES.
19
20There are multiple options available, but on Android we recommend using the
21[Play Services Provider](#tls-on-android) and for non-Android systems we
22recommend [netty-tcnative with
23BoringSSL](#tls-with-netty-tcnative-on-boringssl).
24
25## TLS on Android
26
27On Android we recommend the use of the [Play Services Dynamic Security
28Provider][] to ensure your application has an up-to-date OpenSSL library with
29the necessary cipher-suites and a reliable ALPN implementation. This requires
30[updating the security provider at runtime][config-psdsp].
31
32Although ALPN mostly works on newer Android releases (especially since 5.0),
33there are bugs and discovered security vulnerabilities that are only fixed by
34upgrading the security provider. Thus, we recommend using the Play Service
35Dynamic Security Provider for all Android versions.
36
37*Note: The Dynamic Security Provider must be installed **before** creating a
38gRPC OkHttp channel. gRPC statically initializes the security protocol(s)
39available, which means that changes to the security provider after the first
40channel is created will not be noticed by gRPC.*
41
42[Play Services Dynamic Security Provider]: https://www.appfoundry.be/blog/2014/11/18/Google-Play-Services-Dynamic-Security-Provider/
43[config-psdsp]: https://developer.android.com/training/articles/security-gms-provider.html
44
45### Bundling Conscrypt
46
47If depending on Play Services is not an option for your app, then you may bundle
48[Conscrypt](https://conscrypt.org) with your application. Binaries are available
49on [Maven Central][conscrypt-maven].
50
51Like the Play Services Dynamic Security Provider, you must still "install"
52Conscrypt before use.
53
54```java
55import org.conscrypt.Conscrypt;
56import java.security.Security;
57...
58
59Security.insertProviderAt(Conscrypt.newProvider(), 1);
60```
61
62[conscrypt-maven]: https://search.maven.org/#search%7Cga%7C1%7Cg%3Aorg.conscrypt%20a%3Aconscrypt-android
63
64## TLS on non-Android
65
66OpenJDK versions prior to Java 8u252 do not support ALPN. Java 8 has 10% the
67performance of OpenSSL.
68
69We recommend most users use grpc-netty-shaded, which includes netty-tcnative on
70BoringSSL. It includes pre-built libraries for 64 bit Windows, OS X, and 64 bit
71Linux. For 32 bit Windows, Conscrypt is an option. For all other platforms, Java
729+ is required.
73
74For users of xDS management protocol, the grpc-netty-shaded transport is
75particularly appropriate since it is already used internally for the xDS
76protocol and is a runtime dependency of grpc-xds.
77
78For users of grpc-netty we recommend [netty-tcnative with
79BoringSSL](#tls-with-netty-tcnative-on-boringssl), although using the built-in
80JDK support in Java 9+, [Conscrypt](#tls-with-conscrypt), and [netty-tcnative
81with OpenSSL](#tls-with-netty-tcnative-on-openssl) are other valid options.
82
83[Netty TCNative](https://github.com/netty/netty-tcnative) is a fork of
84[Apache Tomcat's tcnative](https://tomcat.apache.org/native-doc/) and is a JNI
85wrapper around OpenSSL/BoringSSL/LibreSSL.
86
87We recommend BoringSSL for its simplicitly and low occurrence of security
88vulnerabilities relative to OpenSSL. BoringSSL is used by Conscrypt as well.
89
90### TLS with netty-tcnative on BoringSSL
91
92Netty-tcnative with BoringSSL includes BoringSSL statically linked in the
93binary. This means the system's pre-installed TLS libraries will not be used.
94Production systems that have centralized upgrade agility in the face of
95security vulnerabilities may want to use [netty-tcnative on
96OpenSSL](#tls-with-netty-tcnative-on-openssl) instead.
97
98Users of grpc-netty-shaded will automatically use netty-tcnative with
99BoringSSL.
100
101grpc-netty users will need to add the appropriate
102`netty-tcnative-boringssl-static` artifact to the application's classpath.
103Artifacts are available for 64 bit Windows, OS X, and 64 bit Linux.
104
105Depending on netty-tcnative-boringssl-static will include binaries for all
106supported platforms. For Maven:
107
108```xml
109  <dependencies>
110    <dependency>
111      <groupId>io.netty</groupId>
112      <artifactId>netty-tcnative-boringssl-static</artifactId>
113      <version>2.0.20.Final</version> <!-- See table for correct version -->
114      <scope>runtime</scope>
115    </dependency>
116  </dependencies>
117```
118
119And for Gradle:
120
121```gradle
122dependencies {
123  // See table for correct version
124  runtime 'io.netty:netty-tcnative-boringssl-static:2.0.20.Final'
125}
126```
127
128For projects sensitive to binary size, specify the classifier for the precise
129platform you need: `windows-x86_64`, `osx-x86_64`, `linux-x86_64`. You can also
130use [os-maven-plugin](https://github.com/trustin/os-maven-plugin) or
131[osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin),
132to choose the classifier for the platform running the build.
133
134### TLS with netty-tcnative on OpenSSL
135
136Using OpenSSL can have more initial configuration issues, but can be useful if
137your OS's OpenSSL version is recent and kept up-to-date with security fixes.
138OpenSSL is not included with tcnative, but instead is dynamically linked using
139your operating system's OpenSSL.
140
141To use OpenSSL you will use the `netty-tcnative` artifact. It requires:
142
1431. [OpenSSL](https://www.openssl.org/) version >= 1.0.2 for ALPN support.
1442. [Apache APR library (libapr-1)](https://apr.apache.org/) version >= 1.5.2.
145
146You must specify a classifier for the correct netty-tcnative binary:
147`windows-x86_64`, `osx-x86_64`, `linux-x86_64`, or `linux-x86_64-fedora`.
148Fedora derivatives use a different soname from other Linux distributations, so
149you must select the "fedora" version on those distributions.
150
151In Maven, you can use the
152[os-maven-plugin](https://github.com/trustin/os-maven-plugin) to help simplify
153the dependency.
154
155```xml
156<project>
157  <dependencies>
158    <dependency>
159      <groupId>io.netty</groupId>
160      <artifactId>netty-tcnative</artifactId>
161      <version>2.0.20.Final</version> <!-- see table for correct version -->
162      <classifier>${tcnative.classifier}</classifier>
163      <scope>runtime</scope>
164    </dependency>
165  </dependencies>
166
167  <build>
168    <extensions>
169      <!-- Use os-maven-plugin to initialize the "os.detected" properties -->
170      <extension>
171        <groupId>kr.motd.maven</groupId>
172        <artifactId>os-maven-plugin</artifactId>
173        <version>1.7.1</version>
174      </extension>
175    </extensions>
176    <plugins>
177      <!-- Use Ant to configure the appropriate "tcnative.classifier" property -->
178      <plugin>
179        <groupId>org.apache.maven.plugins</groupId>
180        <artifactId>maven-antrun-plugin</artifactId>
181        <executions>
182          <execution>
183            <phase>initialize</phase>
184            <configuration>
185              <exportAntProperties>true</exportAntProperties>
186              <target>
187                <condition property="tcnative.classifier"
188                           value="${os.detected.classifier}-fedora"
189                           else="${os.detected.classifier}">
190                  <isset property="os.detected.release.fedora"/>
191                </condition>
192              </target>
193            </configuration>
194            <goals>
195              <goal>run</goal>
196            </goals>
197          </execution>
198        </executions>
199      </plugin>
200    </plugins>
201  </build>
202</project>
203```
204
205And in Gradle you can use the
206[osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin).
207
208```gradle
209buildscript {
210  repositories {
211    mavenCentral()
212  }
213  dependencies {
214    classpath 'com.google.gradle:osdetector-gradle-plugin:1.4.0'
215  }
216}
217
218// Use the osdetector-gradle-plugin
219apply plugin: "com.google.osdetector"
220
221def tcnative_classifier = osdetector.classifier;
222// Fedora variants use a different soname for OpenSSL than other linux distributions
223// (see http://netty.io/wiki/forked-tomcat-native.html).
224if (osdetector.os == "linux" && osdetector.release.isLike("fedora")) {
225  tcnative_classifier += "-fedora";
226}
227
228dependencies {
229    runtime 'io.netty:netty-tcnative:2.0.20.Final:' + tcnative_classifier
230}
231```
232
233### TLS with Conscrypt
234
235[Conscrypt](https://conscrypt.org) provides an implementation of the JSSE
236security APIs based on BoringSSL. Pre-built binaries are available for 32 and
23764 bit Windows, OS X, and 64 bit Linux.
238
239Depend on `conscrypt-openjdk-uber` for binaries of all supported JRE platforms.
240For projects sensitive to binary size, depend on `conscrypt-openjdk` and
241specify the appropriate classifier. `os-maven-plugin` and
242`osdetector-gradle-plugin` may also be used. See the documentation for
243[netty-tcnative-boringssl-static](#tls-with-netty-tcnative-on-boringssl) for
244example usage of the plugins.
245
246Generally you will "install" Conscrypt before use, for gRPC to find.
247
248```java
249import org.conscrypt.Conscrypt;
250import java.security.Security;
251...
252
253// Somewhere in main()
254Security.insertProviderAt(Conscrypt.newProvider(), 1);
255```
256
257## Enabling TLS on a server
258
259To use TLS on the server, a certificate chain and private key need to be
260specified in PEM format. The standard TLS port is 443, but we use 8443 below to
261avoid needing extra permissions from the OS.
262
263```java
264ServerCredentials creds = TlsServerCredentials.create(certChainFile, privateKeyFile);
265Server server = Grpc.newServerBuilderForPort(8443, creds)
266    .addService(serviceImplementation)
267    .build()
268    .start();
269```
270
271If the issuing certificate authority is not known to the client then a properly
272configured trust manager should be provided to TlsChannelCredentials and used to
273construct the channel.
274
275## Mutual TLS
276
277[Mutual authentication][] (or "client-side authentication") configuration is similar to the server by providing truststores, a client certificate and private key to the client channel.  The server must also be configured to request a certificate from clients, as well as truststores for which client certificates it should allow.
278
279```java
280ServerCredentials creds = TlsServerCredentials.newBuilder()
281    .keyManager(certChainFile, privateKeyFile)
282    .trustManager(clientCAsFile)
283    .clientAuth(TlsServerCredentials.ClientAuth.REQUIRE)
284    .build();
285```
286
287Negotiated client certificates are available in the SSLSession, which is found
288in the `Grpc.TRANSPORT_ATTR_SSL_SESSION` attribute of the call. A server
289interceptor can provide details in the current Context.
290
291```java
292// The application uses this in its handlers.
293public static final Context.Key<MySecurityInfo> SECURITY_INFO = Context.key("my.security.Info");
294
295@Override
296public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
297    Metadata headers, ServerCallHandler<ReqT, RespT> next) {
298    SSLSession sslSession = call.getAttributes().get(Grpc.TRANSPORT_ATTR_SSL_SESSION);
299    if (sslSession == null) {
300        return next.startCall(call, headers);
301    }
302    // This interceptor can provide a centralized policy to process the client's
303    // certificate. Avoid exposing low-level details (like SSLSession) and
304    // instead provide a higher-level concept like "authenticated user."
305    MySecurityInfo info = process(sslSession);
306    return Contexts.interceptCall(
307        Context.current().withValue(SECURITY_INFO, info), call, headers, next);
308}
309```
310
311[Mutual authentication]: http://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake
312
313## Troubleshooting
314
315If you received an error message "ALPN is not configured properly" or "Jetty ALPN/NPN has not been properly configured", it most likely means that:
316 - ALPN related dependencies are either not present in the classpath
317 - or that there is a classpath conflict
318 - or that a wrong version is used due to dependency management
319 - or you are on an unsupported platform (e.g., 32-bit OS). See [Transport
320   Security](#transport-security-tls) for supported platforms.
321
322### Netty
323If you aren't using gRPC on Android devices, you are most likely using `grpc-netty` transport.
324
325If you are developing for Android and have a dependency on `grpc-netty`, you should remove it as `grpc-netty` is unsupported on Android. Use `grpc-okhttp` instead.
326
327If you are on a 32-bit operating system, using Java 11+ may be the easiest
328solution, as ALPN was added to Java in Java 9. If on 32-bit Windows, [Conscrypt
329is an option](#tls-with-conscrypt). Otherwise you need to [build your own 32-bit
330version of
331`netty-tcnative`](https://netty.io/wiki/forked-tomcat-native.html#wiki-h2-6).
332
333If on Alpine Linux and you see "Error loading shared library libcrypt.so.1: No
334such file or directory". Run `apk update && apk add libc6-compat` to install the
335necessary dependency.
336
337If on Alpine Linux, try to use `grpc-netty-shaded` instead of `grpc-netty` or
338(if you need `grpc-netty`) `netty-tcnative-boringssl-static` instead of
339`netty-tcnative`. If those are not an option, you may consider using
340[netty-tcnative-alpine](https://github.com/pires/netty-tcnative-alpine).
341
342If on Fedora 30 or later and you see "libcrypt.so.1: cannot open shared object
343file: No such file or directory". Run `dnf -y install libxcrypt-compat` to
344install the necessary dependency.
345
346Most dependency versioning problems can be solved by using
347`io.grpc:grpc-netty-shaded` instead of `io.grpc:grpc-netty`, although this also
348limits your usage of the Netty-specific APIs. `io.grpc:grpc-netty-shaded`
349includes the proper version of Netty and `netty-tcnative-boringssl-static` in a
350way that won't conflict with other Netty usages.
351
352Find the dependency tree (e.g., `mvn dependency:tree`), and look for versions of:
353 - `io.grpc:grpc-netty`
354 - `io.netty:netty-handler` (really, make sure all of io.netty except for
355   netty-tcnative has the same version)
356 - `io.netty:netty-tcnative-boringssl-static:jar`
357
358If `netty-tcnative-boringssl-static` is missing, then you either need to add it as a dependency, or use alternative methods of providing ALPN capability by reading the *Transport Security (TLS)* section carefully.
359
360If you have both `netty-handler` and `netty-tcnative-boringssl-static` dependencies, then check the versions carefully. These versions could've been overridden by dependency management from another BOM. You would receive the "ALPN is not configured properly" exception if you are using incompatible versions.
361
362If you have other `netty` dependencies, such as `netty-all`, that are pulled in from other libraries, then ultimately you should make sure only one `netty` dependency is used to avoid classpath conflict. The easiest way is to exclude transitive Netty dependencies from all the immediate dependencies, e.g., in Maven use `<exclusions>`, and then add an explict Netty dependency in your project along with the corresponding `tcnative` versions. See the versions table below.
363
364If you are running in a runtime environment that also uses Netty (e.g., Hadoop, Spark, Spring Boot 2) and you have no control over the Netty version at all, then you should use a shaded gRPC Netty dependency to avoid classpath conflicts with other Netty versions in runtime the classpath:
365 - Remove `io.grpc:grpc-netty` dependency
366 - Add `io.grpc:grpc-netty-shaded` dependency
367
368Below are known to work version combinations:
369
370grpc-netty version | netty-handler version | netty-tcnative-boringssl-static version
371------------------ |-----------------------| ---------------------------------------
3721.0.0-1.0.1        | 4.1.3.Final           | 1.1.33.Fork19
3731.0.2-1.0.3        | 4.1.6.Final           | 1.1.33.Fork23
3741.1.x-1.3.x        | 4.1.8.Final           | 1.1.33.Fork26
3751.4.x              | 4.1.11.Final          | 2.0.1.Final
3761.5.x              | 4.1.12.Final          | 2.0.5.Final
3771.6.x              | 4.1.14.Final          | 2.0.5.Final
3781.7.x-1.8.x        | 4.1.16.Final          | 2.0.6.Final
3791.9.x-1.10.x       | 4.1.17.Final          | 2.0.7.Final
3801.11.x-1.12.x      | 4.1.22.Final          | 2.0.7.Final
3811.13.x             | 4.1.25.Final          | 2.0.8.Final
3821.14.x-1.15.x      | 4.1.27.Final          | 2.0.12.Final
3831.16.x-1.17.x      | 4.1.30.Final          | 2.0.17.Final
3841.18.x-1.19.x      | 4.1.32.Final          | 2.0.20.Final
3851.20.x-1.21.x      | 4.1.34.Final          | 2.0.22.Final
3861.22.x             | 4.1.35.Final          | 2.0.25.Final
3871.23.x-1.24.x      | 4.1.38.Final          | 2.0.25.Final
3881.25.x-1.27.x      | 4.1.42.Final          | 2.0.26.Final
3891.28.x             | 4.1.45.Final          | 2.0.28.Final
3901.29.x-1.31.x      | 4.1.48.Final          | 2.0.30.Final
3911.32.x-1.34.x      | 4.1.51.Final          | 2.0.31.Final
3921.35.x-1.41.x      | 4.1.52.Final          | 2.0.34.Final
3931.42.x-1.43.x      | 4.1.63.Final          | 2.0.38.Final
3941.44.x-1.47.x      | 4.1.72.Final          | 2.0.46.Final
3951.48.x-1.49.x      | 4.1.77.Final          | 2.0.53.Final
3961.50.x-1.53.x      | 4.1.79.Final          | 2.0.54.Final
3971.54.x-1.55.x      | 4.1.87.Final          | 2.0.56.Final
3981.56.x-            | 4.1.87.Final          | 2.0.61.Final
399
400_(grpc-netty-shaded avoids issues with keeping these versions in sync.)_
401
402### OkHttp
403If you are using gRPC on Android devices, you are most likely using
404`grpc-okhttp` transport.
405
406Find the dependency tree (e.g., `mvn dependency:tree`), and look for
407`io.grpc:grpc-okhttp`. If you don't have `grpc-okhttp`, you should add it as a
408dependency.
409
410# gRPC over plaintext
411
412An option is provided to use gRPC over plaintext without TLS. While this is convenient for testing environments, users must be aware of the security risks of doing so for real production systems.
413
414# Using OAuth2
415
416The following code snippet shows how you can call the Google Cloud PubSub API using gRPC with a service account. The credentials are loaded from a key stored in a well-known location or by detecting that the application is running in an environment that can provide one automatically, e.g. Google Compute Engine. While this example is specific to Google and it's services, similar patterns can be followed for other service providers.
417
418```java
419// Use the default credentials from the environment
420ChannelCredentials creds = GoogleDefaultChannelCredentials.create();
421// Create a channel to the service
422ManagedChannel channel = Grpc.newChannelBuilder("dns:///pubsub.googleapis.com", creds)
423    .build();
424// Create a stub and send an RPC
425PublisherGrpc.PublisherBlockingStub publisherStub = PublisherGrpc.newBlockingStub(channel);
426publisherStub.publish(someMessage);
427```
428