Assalamualaikum warahmatullahi wabarakatuh, hello everyone! back with me in series practicing my English writing skills, in this article i wanna talk about how Security Implementation could kill your IT Business in just matters of time, Security Implementation is important in every Business that required Web / Desktop / Mobile Application on it, but sometimes how to implement and how to run the security on application business make the flow chaotic and slowly kill your Customer experience.
Is this really happened at real life experience? yes! throughout 2024 i faced multiple case on how the company implementing security in their product (Web / Desktop / Mobile) sometime make the product look miserable. Who’s fault? i don’t think need to finger point to someone for that, since security is long process to go not in time solid product.
Some company always paranoid on their client apps product like product that shipped to their customer it’s like Mobile (.apk, .ios) or Desktop (.exe, .dmp, .jar) they always put big effort on shipped client product, they implementing bunch of security measure but always leave their Server side application (REST API / GRPC / API) with low effort security measure.
Is putting security effort to shipped product wrong? no it’s not in my humble opinion need to make top priority to secure the backend process rather than put big effort first to shipped product. Why i have this opinion? if you put big effort at security measure at backend it’s make the shipped product secure, since all data is put on server. But if company make priority to secure their shipped product the data at backend still vulnerable, for what? just matter of time until someone break the client side protection and everything is done.
Encrypt and Decrypt process at HTTP/s protocol for me always unnecessary even could be the reason for kill the business it self. Encrypt and Decrypt process usually found out at Mobile Application and Desktop Application but this year i faced several Web Application implementing this kind of process also. Is this security effort wrong? no! but unnecessary, for what? protect the traffic? just use SSL, prevent an attacker doing any harm full request? ah it’s just matter of time.
Okay, here’s i will make some real example the Encrypt & Decrypt Process it’s not application security main things.
<?php
include 'crypto.php';
$id = decrypt($_GET['id']);
$query = "SELECT * FROM users WHERE id = ".$id;
######execute########
From the example code above we could see that id
query parameter will pass into direct query, the source of id
is from encrypted things and decrypted to get the raw id
it self, from where’s id
encrypted from clients apps (Android / Desktop / Web) ? yes ofc! if yes, let’s talk again how many risk of the codes from example above? yes 2 main things.
id
variable is pass directly to the raw query?
to pass variable id
it’s make IDOR still exist, btw.How the 2 main vulnerability could happen? yeah simply just edit the source from query parameter id by re-encrypt the original data, every algorithm will always on the client side, it’s nature how Encrypt and Decrypt process works at Client and Server applications. Only that things? no! the Encrypt and Decrypt process generally using AES in every modes at least at Indonesia Company.
Let’s talk about time complexity with Big O notation is how to describe the time efficiency and time complexity of the algorithm that implemented on the application programs, this Big O notation using Mathematic term to describe it here short explanation about Big O Notation:
O(1)
Constant complexity ⇒ Time execution it’s not depends on how big the input. O(log n)
Logarithmic complexity ⇒ Time execution it’s increased as long as the logarithmic inputO(n)
Linear complexity ⇒ Time execution depends on how big the input In this case O(1)
[ Constant complexity ] is implemented in indexing array get value, don’t care how big the array size if we supply index the time complexity remaining same. But the O(n)
[ Linear complexity ] it’s not most encryption / decryption process is using O(n)
complexity. Let’s take a look
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
import time
def encrypt_aes_cbc(data, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
return cipher.encrypt(pad(data, AES.block_size))
def main():
key = get_random_bytes(16)
iv = get_random_bytes(16)
multipliers = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000]
for n in multipliers:
data = b'N' * n
start_time = time.time()
encrypted_data = encrypt_aes_cbc(data, key, iv)
end_time = time.time()
execution_time = (end_time - start_time) * 1000
print(f"Encrypt N*{n} selesai, dengan time execution selama {execution_time:.2f} ms")
if __name__ == "__main__":
main()
Here’s the simple program with python3 to encrypt with library pycryptodome
and doing AES CBC encryption process to demonstrate time complexity, if we run the program we could see time execution will increased depends how long the input strings.
We could see the time execution only ~200 milliseconds, less than a 1 seconds isn’t? yeah how about make the multiplier much higher and adding the decrypt process to see how much time execution each process it self.
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import time
def encrypt_aes_cbc(data, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
return cipher.encrypt(pad(data, AES.block_size))
def decrypt_aes_cbc(encrypted_data, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(encrypted_data), AES.block_size)
def main():
key = get_random_bytes(16)
iv = get_random_bytes(16)
multipliers = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000]
for n in multipliers:
data = b'N' * n
start_time = time.time()
encrypted_data = encrypt_aes_cbc(data, key, iv)
end_time = time.time()
encryption_time = (end_time - start_time) * 1000 # Konversi ke milidetik
print(f"Encrypt N*{n} selesai, dengan time execution selama {encryption_time:.2f} ms")
start_time = time.time()
decrypted_data = decrypt_aes_cbc(encrypted_data, key, iv)
end_time = time.time()
decryption_time = (end_time - start_time) * 1000 # Konversi ke milidetik
print(f"Decrypt N*{n} selesai, dengan time execution selama {decryption_time:.2f} ms")
assert data == decrypted_data, "Maaf gagal"
if __name__ == "__main__":
main()
and if we run the codes again the time execution it’s not that matters again but the memory consume of the application is the serious problem here you can take a looks this screenshot below
5.688.7 MB memory usage about just for doing encrypt and decrypt process, now image the REST API application with encrypt and decrypt process from the client’s what’s the attack vector? Throughout 2024 I’m always shutdown the entire company REST API Core Service just sending input N with longer multipliers with multi thread and multi connections. Now imagine inputting N*1000000000
will cost 1.64 Seconds, image sending N*1000000000
in 200 connection (200 * 1.64 seconds = 328 seconds or equal with 5 minutes delay per seconds) in one minutes how the server react? yeah, down.
So be wise to implementing the Encrypt and Decrypt process at your business, because instead of secure your whole server could down in maybe yeah 2 minutes in this type of attack. But! if you already implement this kind of business process the best way to prevent this attack is checking the raw of encrypted
data from the users, if the that logically damn long just deny the request and return error, don’t pass it to the decrypt process!
Customer Experience is very important part in Established Business, an example of delay process in 1 seconds could make existing customer feel like your applications is slow enough and will thinking to your competitor with similar business models. Customer Experience here is hard things to be maintained, delay it’s not about the process behind how if the delay came from the Security Posture that implemented to make your application secure? i will not talking about WAF could make your response slower haha.
Let’s talk about Rate Limiting this is mechanism for deny a request when the count of total request from the users it’s on the maximum amount of allowed request per / (seconds, minutes, hours). Usually the method to implementing the Rate Limiting to client is matching to this 4 identifiers:
But all of this 4 identifier above, points number 1 is the very common way to implementing this kind of Rate Limiting, the IP Address request from client to the server will be watched by the layer of network and deny the request if they filled the maximum amount of the request allowed. The problem is, IP Address from clients is assigned by the ISP (Internet Service Provider) many of users is have a same IP Address since the ISP will assigned 1 IP to could be every users in subdistrict.
Now imagine if you have 10 customers at subdistrict name “Darjo”, all of them using same ISP since the ISP regulation is monopolies by them. Since you are implementing based on IP Address one of users got rate limiting by spamming request to endpoint and also impacted to 9 others customers, this is nature risk of doing Rate Limit based on IP Addresses.
So the solution is? rate limiting by others identifier? with what? User-Agent? it’s client based came from the client http (browser and more) it’s quite same every devices imagine from 10 the 5 person have same identifier User Agent from same type devices still lose 5 persons. Implementing others identifier? yeah this is some right way how to do it? by the current session when authenticated quite hard to implement but this is some right way to do, since the identifier is the right person.
There’s ultimately wrong way to implement Rate Limit rather than patching the actual risk of security on the application, Rate Limit not supposed to be how to patch the risk of security findings, but it’s another layer security implementation. Findings is Findings need to be patched by changing the algorithm or adding some logic to prevent the abuse function happen, there’s some example of Rate Limit not the solutions of vulnerability:
@app.route('/forgot-password', methods=['POST'])
def forgot_password():
email = request.json.get('email', None)
if not email:
return jsonify({"error": "Email is required"}), 400
if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
return jsonify({"error": "Invalid email format"}), 400
if email not in users_db:
return jsonify({"error": "Email not found"}), 404
send_email_recovery(email)
print(f"Sending password reset email to {email}")
return jsonify({"message": "Password reset email sent"}), 200
At this example of code how to implementation Forget Password features, in slight of the eyes there’s no vulnerability on the codes, the flow is normal and right, checking the email is exist of not, validate the type of email is match on regex or not (even you could bypass the validation) sending by email the recovery email, everything looks normal. But! there’s some issue with the design of the application flow, the attack scenario is what if an attacker sending the same request of the email like 1000 per minutes, imagine how much cost resource wasted by this attack? okay, how to prevent it? to implementing rate limiting with session? no! you couldn’t since the users it’s not authenticated! Want to implementing rate limiting based on IP Addresses? No! others user might be have a same IP Addresses since they are at the same region. How to patch the flaws? by adding the logic, by change the flow! Here’s the method
@app.route('/forgot-password', methods=['POST'])
def forgot_password():
max_attempt_per_day = 5
email = request.json.get('email', None)
if not email:
return jsonify({"error": "Email is required"}), 400
if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
return jsonify({"error": "Invalid email format"}), 400
if email not in users_db:
return jsonify({"error": "Email not found"}), 404
if count(attempt_forget(email)) >= 5:
return jsonify({"error": "Too much request"}), 401
send_email_recovery(email)
add_attempt_forget(email)
print(f"Sending password reset email to {email}")
return jsonify({"message": "Password reset email sent"}), 200
This is how the right way to patch the flaw of the algorithm, by saving every attempt of try to forget password to a database and checking this day how many the email want to reset the password, if reach maximum policy just deny it. Rate Limit not always the solutions when patch some vulnerability but worth enough to implementing when is right to do it.
Pentesting (Penetrationg Testing) is way a process to test the application is secure enough or not BEFORE or ON THE WAY when the application is aired or used by the customers. Normally Pentesting is done before the Application or the Features is aired to customers / users. But quite a few also do pentesting when the application goes live it’s big deal but better than nothings.
So the problem is the limitation when doing pentesting, usually clients always want to put their security posture hard efforts to their development environment when penetration testing process is in progress is put the security posture efforts (WAF [Web Application Firewall], Firewall, Anti Viruse, EDR, XDR) is wrong? no absolutely not, but not in penetration testing process. Why? because the pentester it’s not going test how good the security implementation of the Security Posture but the Application it self.
Here’s the example vulnerable codes that could be founded early on penetration testing process but not founded since the the WAF it’s prevent the injection attempt by the pentester
var user User
err = db.QueryRow("SELECT id, name FROM users WHERE id = "+ id).Scan(&user.ID, &user.Name)
if err != nil {
return 404, "data not found"
}
return 200, user.id + "found"
This type of codes is vulnerable to SQL Injection, but the return error it’s not return error SQL but the error logic that data it’s not found when pentester input the single quotes (’) attempts. It’s pentester have a limited testing methodology to verify the findings? not! but most of WAF it’s deny the request when it match to their rules of threat. WAF will limit the attack scenario to verify the findings is valid or not even actually it’s valid.
So? the WAF it’s a good things to prevent attack isn’t? YES! ofc, but the idea it’s not prevent the attack but patching the vulnerability. WAF will not forever ‘prevent’ attack and vulnerable side, just matters of time there will be a way to bypass the WAF, it’s proofed day after day in this Cyber Security Industries. So don’t implement any WAF at development environment when penetration testing process is in timelines.
Encrypt and Decrypt process is good security layer to prevent data changes on the fly, but it’s not a way to patching the vulnerability also it’s need to be treated good on the how to implementing it on the application but still it’s a good way to make an attacker spend much time to doing research the way to break it, good strategies to wasting attacker time.
Rate limiting is also good security layer to be implemented, but what identifier to be used it’s quite challenging to research how to find a right identifier, for me every vulnerability couldn’t be patched with this kind of security layers.
WAF , Firewall and Anti virus it’s very good security layers to be implemented to production application that faced to the customers, but in penetration testing process on development environment the Firewall things it’s not necessary to be implemented, bunch findings on penetration process is betters than have a fraudulent at the production that cost the Brand Images or the Financial services.
So this is end of this article about how security implementation on established business could kill your business just matters of time, security is long process to go not the perfect product in time. Thank you for reading this article, sorry if this article not full fill what your expectation, i hope I’m doing less typos or grammar error rather than 2 previous article! <3