quixxi 1.0.0 copy "quixxi: ^1.0.0" to clipboard
quixxi: ^1.0.0 copied to clipboard

Flutter plugin for adding SSL Pinning to application, Prevent copy and paste inside the application, Prevent misuse of APIs using API attestion

Quixxi Plugin #

The Flutter plugin provides the following security enhancements for mobile applications:

SSL Pinning #

  • Ensures secure communication between the application and backend servers by validating the server certificate against a pinned public key.

  • Protects against man-in-the-middle (MITM) attacks by preventing connections to unauthorized servers.

Clipboard Protection #

  • Prevents copy and paste actions inside the application to safeguard sensitive information such as passwords, tokens, or personal data.

  • Reduces the risk of data leakage through clipboard monitoring or malicious apps.

API Attestation #

  • Protects backend APIs from misuse by validating requests through Secure HashKey attestation.

  • Ensures that only genuine, untampered applications can communicate with the server.

  • Helps prevent unauthorized API calls and mitigates replay or injection attacks.

Integration Notes #

Important #

Quixxi Security Shield must be applied after integrating this plugin into your application.

SSL Pinning #

  • Debug Builds

    • SSL certificate validation is not enforced.

    • This is intentional to simplify development and testing.

  • Release Builds

    • Quixxi Shield must be applied.

    • Enforces SSL Pinning and strong runtime protections.

API Attestation #

  • In Debug Mode, a default hardcoded hash key is used:
MNaiMYHqVH3ZLVfGVc4nqFcd7Gf8Avr6JePPUJZYfrCA7A00GiRSFTPC981P7Vpe1gDUh9YQaKEE2ihGp04GfW7EB2HJx8JVkwv5k1fvDhaQNMetvaFACAw70gP61KYK
  • Use this key only for development and testing.

  • In Production Builds, configure and use SecureHash Key generated on Quixxi portal to protect against API misuse.

Getting Started #

Add quixxi as a dependency in your pubspec.yaml:

dependencies:
  quixxi: 1.0.0

Usage example #

SSL Pinning #

Using Dio

import 'package:quixxi/services.dart';

Dio dioClient = getDioClient('https://gorest.co.in',enableSSLPinning: true);

void apiCall() async {
    var header = {'Content-type': 'application/json; charset=utf-8'};

    try {
      final response = await dio.get("https://yourdomain.com/yourapi",
          options: Options(headers: header));
      if (response.statusCode == 200) {
        apiResponse.value = response.data.toString();
      } else {
        print('${response.statusCode} : ${response.data.toString()}');
        apiResponse.value = response.data.toString();
      }
    } catch (error) {
      apiResponse.value = error.toString();
    }
  }

Using Http

import 'package:quixxi/services.dart';

SecureHttpClient secureHttpClient = getSecureHttpClient(enableSSLPinning: true);

void apiCall2() async{
     var header = {'Content-type': 'application/json; charset=utf-8'};

    try {
        Uri uri = Uri.parse("https://gorest.co.in/public/v2/todos");
        final response = await secureHttpClient.get(uri, headers: header);
        if (response.statusCode == 200) {
          apiResponse.value = response.body.toString();
        }else{
            print('${response.statusCode} : ${response.body.toString()}');
            apiResponse.value = response.body.toString();
        }
    } catch (error) {
      apiResponse.value = error.toString();
    }
}

Custom Implementation

import 'package:quixxi/services.dart';

Future myCustomImplementation(String url, Map<String,String> headers) async {
  try{
    final secure = await SSLCertificatePinning().check(
      serverURL: url,
      headerHttp: headers,
      timeout : 50
    );

    if(secure.contains("CONNECTION_SECURE")){
      return true;
    }else{
      return false;
    }
  }catch(e){
    return false;
  }
}

API Attestation #

You can enable API Attestation to automatically send a secure hash (from Quixxi) either in the request header or payload.

With SSLPinning

Using Dio
import 'package:quixxi/services.dart';

// Enable App Attestation and configure hash injection
Dio dioClient = getDioClient(
  'https://gorest.co.in',
  enableSSLPinning: true,
  enableAppAttestation: true,
  sendHashInHeader: true,   // or false
  sendHashInPayload: false, // or true
);

void apicall_dio_app_attestation() async {
  var header = {'Content-type': 'application/json; charset=utf-8'};
  try {
    final response = await dioClient.get(
      urlTextEditingController.text,
      options: Options(headers: header),
    );
    apiResponse.value = response.data.toString();
  } catch (error) {
    apiResponse.value = error.toString();
  }
}
Using Http
import 'package:quixxi/services.dart';

SecureHttpClient secureHttpClient = getSecureHttpClient(
  enableSSLPinning: true,
  enableAppAttestation: true,
  sendHashInPayload: true, // or sendHashInHeader: true
);

void apicall_http_app_attestation() async {
  var header = {'Content-type': 'application/json; charset=utf-8'};
  try {
    Uri uri = Uri.parse(urlTextEditingController.text);
    final response = await secureHttpClient.get(uri, headers: header);
    apiResponse.value = response.body.toString();
  } catch (error) {
    apiResponse.value = error.toString();
  }
}

Without SSLPinning

Same usage, but dont pass enableSSLPinning. it is set to false by default.

SOAP API Support

App Attestation also works with SOAP requests. Just set "Content-Type": "text/xml; charset=utf-8" in headers and provide your envelope.

Using Dio

String soapEnvelope({String? bodyContent}) => '''
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    ${bodyContent ?? ''}
  </soap:Body>
</soap:Envelope>
''';

// Enable App Attestation and configure hash injection
Dio dioClient = getDioClient(
  'https://httpbin.org',
  enableAppAttestation: true,
  sendHashInHeader: true,   // or false
  sendHashInPayload: false, // or true
);

void apicall_dio_soap_with_header() async {
  try {
    isLoading.value = true;

    String envelope = soapEnvelope(bodyContent: '<Test>Hello</Test>');

    final response = await dioClient.post(
      "https://httpbin.org/post",
      data: envelope,
      options: Options(
        headers: {
          'Content-Type': 'text/xml; charset=utf-8',
          'SOAPAction': 'urn:TestAction'
        },
      ),
    );

    isLoading.value = false;
    apiResponse.value = response.data.toString();
  } catch (error) {
    isLoading.value = false;
    apiResponse.value = error.toString();
  }
}
Using Http
  String soapEnvelope({String? bodyContent}) => '''
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    ${bodyContent ?? ''}
  </soap:Body>
</soap:Envelope>
''';

// Enable App Attestation and configure hash injection
SecureHttpClient secureHttpClient = getSecureHttpClient(
  enableAppAttestation: true,
  sendHashInPayload: true, // or sendHashInHeader: true
);

void apicall_http_soap_with_payload() async {
  try {
    isLoading.value = true;

    // Inject SecureHash inside <soap:Body>
    String envelope = soapEnvelope(
      bodyContent: '<Test>Hello</Test>',
    );

    Uri uri = Uri.parse("${urlTextEditingController.text}/post");

    final response = await secureHttpClientWithHashInPayload.post(
      uri,
      headers: {
        'Content-Type': 'text/xml; charset=utf-8',
        'SOAPAction': 'urn:TestAction',
      },
      body: envelope,
    );

    isLoading.value = false;
    apiResponse.value = response.body;
  } catch (error) {
    isLoading.value = false;
    apiResponse.value = error.toString();
  }
}

Copy & Paste Prevention #

Secure Text Field


import 'package:flutter/material.dart';
import 'package:quixxi/text_field/quixxi_text_form_field.dart';

class ExamplePage extends StatelessWidget {
  const ExamplePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Quixxi Example')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Quixxi Textfield'),
            Container(
              padding: const EdgeInsets.symmetric(vertical: 15),
              Container(
                padding: const EdgeInsets.symmetric(vertical: 15),
                child: QuixxiTextField(
                  decoration: const InputDecoration(
                    border: UnderlineInputBorder(),
                    hintText: 'https://yourdomain.com',
                  ),
                  keyboardType: TextInputType.url,
                  textInputAction: TextInputAction.next,
                  controller: TextEditingController(
                          text: "https://yourdomain.com"),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Secure Text Form Field


import 'package:flutter/material.dart';
import 'package:your_package/quixxi_text_form_field.dart'; // adjust the import

class ExamplePage extends StatelessWidget {
  const ExamplePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Quixxi Example')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Quixxi TextFormfield'),
            Container(
              padding: const EdgeInsets.symmetric(vertical: 15),
              child: QuixxiTextFormField(
                decoration: const InputDecoration(
                  border: UnderlineInputBorder(),
                  hintText: 'https://yourdomain.com',
                ),
                keyboardType: TextInputType.url,
                textInputAction: TextInputAction.next,
                controller: TextEditingController(
                  text: "https://yourdomain.com",
                ),
                onSaved: (value) {},
                validator: (value) {},
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Configuration Parameters #

When creating a Dio client with getDioClient or an Http client with getSecureHttpClient, you can configure the following options:

Parameter Type Default Description
enableSSLPinning bool false Enables SSL certificate pinning (requires Quixxi Shield in release build).
enableAppAttestation bool false Enables App Attestation, which sends a secure hash from Quixxi.
sendHashInHeader bool false If true, the secure hash is sent in the HTTP/SOAP headers.
sendHashInPayload bool false If true, the secure hash is injected into the request payload (JSON or SOAP <soap:Body>).
baseUrl (Dio only) String Base URL for all API calls made with Dio client.

Adding Quixxi Shield to application #

  • Create an account in https://portal.quixxi.com
  • Create application container in your account.
  • Upload your application to portal for app protection.
  • For SSL Pinning, choose the option SSL certificate validation via SSLPinning in Shield configuration
  • For API Attestation, choose the option API attestation in Shield configuration
  • After applying shield configurations, wait for Shielding to complete
  • Download protected application from portal.
6
likes
130
points
413
downloads

Publisher

verified publisherquixxi.com

Weekly Downloads

Flutter plugin for adding SSL Pinning to application, Prevent copy and paste inside the application, Prevent misuse of APIs using API attestion

Homepage

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

convert, dio, encrypt, flutter, http, plugin_platform_interface, pointycastle, string_validator

More

Packages that depend on quixxi

Packages that implement quixxi