Encountering the CERTIFICATE_VERIFY_FAILED error in Flutter while making POST requests can be a frustrating experience for developers. This error indicates that your Flutter app is unable to establish a secure connection with the server due to issues with SSL certificate verification. This problem often arises when the server’s SSL certificate is self-signed, expired, or issued by an untrusted Certificate Authority (CA). Understanding the root cause and implementing the correct solutions are crucial for ensuring secure and reliable communication between your Flutter application and the backend server. This article provides a comprehensive guide to diagnosing and resolving the Flutter CERTIFICATE_VERIFY_FAILED error, ensuring your POST requests are securely executed.
Understanding the CERTIFICATE_VERIFY_FAILED Error
The CERTIFICATE_VERIFY_FAILED error is a security feature designed to protect your application from man-in-the-middle attacks. When your Flutter app attempts to connect to a server over HTTPS, it verifies the server’s SSL certificate against a list of trusted CAs. If the certificate cannot be validated, the error is thrown, preventing the connection. This validation process is crucial for ensuring that you are communicating with the intended server and that your data is encrypted and protected. The error message usually includes details about the certificate issue, such as “unable to get local issuer certificate” or “certificate has expired,” which can provide valuable clues for troubleshooting. Ignoring this error can expose your application to significant security risks, making it essential to address it promptly and correctly. The error is particularly common during development when using self-signed certificates for local testing, but can also occur in production environments due to misconfigured servers or outdated CA bundles.
Several factors can trigger the CERTIFICATE_VERIFY_FAILED error. The most common reason is the use of self-signed certificates, which are often used in development environments for testing purposes. These certificates are not issued by a trusted CA, so Flutter’s default SSL verification process will reject them. Another potential cause is an expired SSL certificate on the server. All SSL certificates have an expiration date, and if the certificate is expired, browsers and applications will display warnings or errors. Furthermore, the server might be using a certificate issued by a CA that is not recognized by the Flutter app’s underlying operating system. This can happen if the CA is relatively new or not widely trusted. Finally, incorrect server configuration or network issues can also lead to this error. Understanding these potential causes is the first step in effectively resolving the CERTIFICATE_VERIFY_FAILED error.
For instance, consider a scenario where a developer is building a Flutter app that communicates with a local server running on their development machine. They’ve generated a self-signed certificate for HTTPS on their server. When the Flutter app attempts to make a POST request to this server, it encounters the CERTIFICATE_VERIFY_FAILED error because the self-signed certificate is not trusted by default. To resolve this, the developer would need to either configure Flutter to trust the self-signed certificate or obtain a valid certificate from a trusted CA. This example illustrates the importance of understanding the error and implementing the appropriate solution.
Common Solutions to Resolve the Error
There are several approaches to resolving the CERTIFICATE_VERIFY_FAILED error in Flutter. The most appropriate solution depends on the specific cause of the error and the environment in which the application is running. Here are some common solutions:
- Trusting Self-Signed Certificates: In development environments, you can configure your Flutter app to trust self-signed certificates. This involves creating a custom SecurityContext and overriding the badCertificateCallback to allow connections to servers with untrusted certificates.
- Updating CA Certificates: Ensure that your operating system and Flutter app have the latest CA certificates. Outdated certificates can cause verification failures with valid SSL certificates.
- Obtaining Valid SSL Certificates: For production environments, always use valid SSL certificates issued by a trusted CA. Services like Let’s Encrypt provide free and easy-to-use SSL certificates.
One approach involves creating a custom SecurityContext and overriding the badCertificateCallback. This callback allows you to define custom logic for handling invalid certificates. By returning true in the callback, you instruct the Flutter app to trust the certificate despite the verification failure. However, this approach should only be used in development environments, as it bypasses security checks and can expose your application to risks in production. Here’s how you might implement this approach:
- Create a custom SecurityContext.
- Set the badCertificateCallback to return true.
- Pass the SecurityContext to the HttpClient used for making the POST request.
Another solution involves updating the CA certificates on the device or emulator running the Flutter app. Outdated CA certificates can cause verification failures even with valid SSL certificates. On Android emulators, you can update the CA certificates by installing the latest system updates. On physical devices, the CA certificates are typically updated automatically by the operating system. Making sure you have the latest operating system version can mitigate this problem.
Implementing Solutions in Flutter Code
Implementing these solutions in your Flutter code requires modifying the HttpClient used for making the POST request. You’ll need to create a custom SecurityContext and configure it to trust self-signed certificates or update the CA certificates used by the HttpClient. Here’s an example of how to trust self-signed certificates in a development environment:
dart import ‘dart:io’; void main() async { final sslContext = SecurityContext.defaultContext ..badCertificateCallback = (X509Certificate cert, String host, int port) => true; final httpClient = HttpClient(context: sslContext); final request = await httpClient.postUrl(Uri.parse(‘https://your-self-signed-server.com/api')); final response = await request.close(); final responseBody = await response.transform(utf8.decoder).join(); print(responseBody); }
This code snippet demonstrates how to create a custom SecurityContext that trusts all certificates, regardless of their validity. The badCertificateCallback is set to a function that always returns true, effectively bypassing the SSL verification process. This approach should only be used in development environments. For production environments, you should obtain a valid SSL certificate from a trusted CA.
To update the CA certificates used by the HttpClient, you can use the SecurityContext.defaultContext to access the system’s default CA certificates. You can also add custom CA certificates to the SecurityContext if needed. However, this is typically not necessary unless you are working with a private CA that is not included in the system’s default CA bundle. Using the system’s default CA certificates ensures that your Flutter app trusts the same CAs as other applications on the device. Always ensure your operating system and Flutter app have the latest CA certificates.
Best Practices and Security Considerations
When dealing with SSL certificate verification in Flutter, it’s crucial to prioritize security and follow best practices. Bypassing SSL verification, even in development environments, can create a false sense of security and lead to vulnerabilities in production. Always strive to use valid SSL certificates from trusted CAs in production environments. Never disable SSL verification entirely, as this can expose your application to man-in-the-middle attacks. According to OWASP, improper SSL validation is a common vulnerability that can lead to data breaches and other security incidents. OWASP provides valuable resources and guidelines for secure development practices.
Here are some key considerations to keep in mind:
- Use Valid SSL Certificates in Production: Always obtain SSL certificates from trusted CAs for production environments.
- Avoid Bypassing SSL Verification in Production: Never disable or bypass SSL verification in production, as this can expose your application to security risks.
- Regularly Update CA Certificates: Keep your operating system and Flutter app’s CA certificates up to date to ensure compatibility with the latest SSL certificates.
In addition to these best practices, it’s also important to implement other security measures, such as using HTTPS for all communication, validating server responses, and protecting sensitive data. Portswigger Web Security Academy offers comprehensive training on web security vulnerabilities and mitigation techniques. By following these guidelines, you can ensure that your Flutter app is secure and protected from common security threats. Remember, security is an ongoing process, and it’s essential to stay informed about the latest security threats and best practices. You can also find valuable resources on Let’s Encrypt for obtaining free SSL certificates.
Featured Snippet: To resolve the Flutter CERTIFICATE_VERIFY_FAILED error, especially when dealing with self-signed certificates in development, create a custom SecurityContext and override the badCertificateCallback to return true. This tells Flutter to trust the certificate despite the verification failure. Important: Use this method only in development to avoid security vulnerabilities in production. Ensure you obtain valid SSL certificates from trusted CAs for production deployments.
FAQ Section
- What causes the CERTIFICATE\_VERIFY\_FAILED error in Flutter?
- The error occurs when Flutter cannot verify the SSL certificate of the server it's trying to connect to. This can be due to self-signed certificates, expired certificates, or certificates issued by untrusted CAs.
- How can I trust self-signed certificates in Flutter?
- You can create a custom SecurityContext and override the badCertificateCallback to return true. This should only be done in development environments.
- Is it safe to disable SSL verification in production?
- No, disabling SSL verification in production is highly discouraged as it exposes your application to security risks.
- How do I obtain a valid SSL certificate for my server?
- You can obtain a valid SSL certificate from a trusted CA, such as Let's Encrypt. These certificates are free and easy to install.
Question & Answer :
I am sending a post request in Dart. It is giving a response when I test it on API testing tools such as Postman. But when I run the app. It gives me the following error:-
E/flutter ( 6264): HandshakeException: Handshake error in client (OS Error: E/flutter ( 6264): CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:363))
Here is my code of the function -
Future getAccessToken(String url) async { try { http.post('url', body: { "email": "<a class="__cf_email__" data-cfemail="afd7d6d5efd7d6d581cad7cec2dfc3ca" href="/cdn-cgi/l/email-protection">[email protected]</a>", "password": "1234" }).then((response) { print("Reponse status : ${response.statusCode}"); print("Response body : ${response.body}"); var myresponse = jsonDecode(response.body); String token = myresponse["token"]; }); } catch (e) { print(e.toString()); }
Here’s the full error body:
E/flutter ( 6264): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception: E/flutter ( 6264): HandshakeException: Handshake error in client (OS Error: E/flutter ( 6264): CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:363)) E/flutter ( 6264): #0 IOClient.send (package:http/src/io_client.dart:33:23) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #1 BaseClient._sendUnstreamed (package:http/src/base_client.dart:169:38) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #2 BaseClient.post (package:http/src/base_client.dart:54:7) E/flutter ( 6264): #3 post.<anonymous closure> (package:http/http.dart:70:16) E/flutter ( 6264): #4 _withClient (package:http/http.dart:166:20) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #5 post (package:http/http.dart:69:5) E/flutter ( 6264): #6 _MyLoginFormState.getAccessToken (package:chart/main.dart:74:7) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #7 _MyLoginFormState.build.<anonymous closure> (package:chart/main.dart:64:29)
In order to enable this option globally in your project, here is what you need to do:
- In your main.dart file, add or import the following class:
import 'dart:io';
class MyHttpOverrides extends HttpOverrides{ @override HttpClient createHttpClient(SecurityContext? context){ return super.createHttpClient(context) ..badCertificateCallback = (X509Certificate cert, String host, int port)=> true; } }
- In your main function, add the following line after function definition:
HttpOverrides.global = MyHttpOverrides();
Your main.dart should look like this
void main() { // Your code HttpOverrides.global = MyHttpOverrides(); runApp(const ConsultationApp()); }
This comment was very helpful to pass through this matter, and please note that…
This should be used while in development mode, do NOT do this when you want to release to production, the aim of this answer is to make the development a bit easier for you, for production, you need to fix your certificate issue and use it properly, look at the other answers for this as it might be helpful for your case.