Security Best Practices
Due to the sensitive data we use on the client side, such as "private key" and "amount," we are open to attack via a reverse engineering. Therefore, we must secure our application.
Secure App Payment Type
# Securing Only Premium Feature
- as much as possible, verify whether the user has made a app purchase in every activity. This is to prevent the user from using the app without paying.
To check if user has made a app purchased,
ChapaUtil.isCurrentPlanIn("your-app-plan-name","other-valid-plan","....")
method. It returnstrue
if user has made a app purchase on the listed app-plans andfalse
if user hasn't made in listed app-plan a payment.
- Method 1
on Activity onCreate
method, check if user has made a app purchase. If user hasn't made a app purchase, redirect user to PaymentActivity
or Close the app
.
- Method 2
the above method is repetitive, so we can create a BaseActivity
class and extend ALL ACTIVITY that require purchase from it. Then in BaseActivity
class, check if user has made a app purchase. If user hasn't made a app purchase, redirect user to PaymentActivity
or Close the app
.
public class BasicActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!ChapaUtil.isCurrentPlanIn("Premium")) {
// to redirect user to payment activity
Intent intent = new Intent(this, PaymentActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
// to Exit the app
// System.exit(0);
// to close current activity
// finish();
// or you can do anything you want
}
}
}
// USAGE
// change every activity require app-purchase to extend BasicActivity
class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!ChapaUtil.isCurrentPlanIn("Premium")) {
// to redirect user to payment activity
val intent = Intent(this, PaymentActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
// to Exit the app
// System.exit(0);
// to close current activity
// finish();
// or you can do anything you want
}
}
}
// USAGE
// change every activity require app-purchase to extend BasicActivity
Encrypt Payment Data
- Encrypt
Amount
andchapa secret Key
anditem-key
.
To encrypt data, useCipher.encrypt
method.
Log.d("Encrypted ",
"amount" + Cipher.encrypt(this,"19.9") +
"item-key" + Cipher.encrypt(this,"gold") +
"item-value" + Cipher.encrypt(this,"300"));
// copy the logged encrypted data from logcat
try {
ItemPayment gold = new ItemPayment(
this,
Double.parseDouble(Cipher.decrypt(this, "C5F373E141957172C4F130A65BFE70B9")), // amount
Cipher.decrypt(this, "DAABD31A834EEC8E3EE29C819AFD6091"), // itemKey
Integer.parseInt(Cipher.decrypt(this, "E6D33CB6CBFB48212745A53469AC5CC0")), // itemValue
ItemProperties.ADD
);
} catch (ChapaError e) {
e.printStackTrace(); // UNSUPPORTED DATA-TYPE
}
Log.d("Encrypted ",
"amount ${Cipher.encrypt(this,"19.9")}" +
"item-key ${Cipher.encrypt(this,"gold")}" +
"item-value ${Cipher.encrypt(this,"300")}")
// copy the logged encrypted data from logcat
try {
val gold = ItemPayment(
this,
Cipher.decrypt(this, "C5F373E141957172C4F130A65BFE70B9").toDouble(), // amount
Cipher.decrypt(this, "DAABD31A834EEC8E3EE29C819AFD6091"), // itemKey
Cipher.decrypt(this, "E6D33CB6CBFB48212745A53469AC5CC0").toInt(), // itemValue
ItemProperties.ADD
)
} catch (e: ChapaError) {
Log.e("Error", e.message) // UNSUPPORTED DATA TYPE
}
Other Security Best Practice
- Always Use
Proguard
to obfuscate your code. This will make it harder for attackers to reverse engineer your code. Learn more
Learn more about App Security Best Practice