From HTML websites in the 1980s to progressive web apps in 2024, web development has come a long way. And as client-side capabilities have improved, so has the importance of security. We may get away with poor security on a static HTML page but modern websites store cookies, passwords, credit card information, and other data. As such, security for the client is more important than ever.
This article provides a high-level summary of client security. The article covers the following topics:
- Input validation
- User Authentication
- User Authorization
- Data protection
- Secure communication
Each section has a description and a few techniques that you can implement. The article also offers a few code snippets in JavaScript. These code snippets are for demonstration purposes only.
Finally, I hope you enjoy reading this article. I certainly enjoyed writing it.
Input Validation
Input validation is the process of filtering what users input into an application. Essential for client-side security, input validation is required but more is needed.
Consider the following scenario:. Someone wants to attack your website with a virus. So they go on the 'contact us' form. They then input characters that the browser will interpret as code and execute. Now your website is executing code that you did not design. This leads to all sorts of strange behavior, including stolen user data.
Whitelisting vs Blacklisting
You could avoid all this by ensuring no malicious input enters your website. You could use any whitelisting technique. This means that you have a list of characters that the website allows. Anything else will be rejected. You could also use a blacklisting technique. A blacklist contains a list of characters that are NOT allowed. Generally, whitelisting is safer than blacklisting because blacklisting is more susceptible to filter evasion
Semantic and Syntactic Validity
Any good input validation technique should also ensure both syntax and semantic validity. syntax validity ensures that an input is in the correct form or type. E.g., The CVV code for a credit card must always be three digits. Semantic validity ensures that the imputed data follows the correct context or order. For example, the expiration date of a debit card should always be a future date.
Common input validation techniques
Now that you understand the basics of input validation, let us review some common techniques.
- Built-in validation: involves the use of inbuilt HTML attributes such as required, pattern, type, min-length, max-length, pattern, and so on. Read more here
<!-- Requiring a field -->
<input type="text" name="username" required>
<!-- Setting a pattern for input -->
<input type="text" name="phone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}">
<!-- Limiting input length -->
<input type="text" name="zipcode" minlength="5" maxlength="9">
- Sanitization: involves cleaning up an input that contains suspicious characters. Read more here
// Code to remove HTML tags from input
function sanitizeInput(input) {
return input.replace(/</g, '<').replace(/>/g, '>');
}
// Code to remove leading/trailing whitespace and limit to alphanumeric
function sanitizeUsername(username) {
return username.trim().replace(/[^a-zA-Z0-9]/g, '');
}
- Regular Expressions (REGEX): useful for imposing a pattern in which data must be input. Only data that matches the preset pattern will be accepted! Regex is typically used for zip code or password form fields. Here is an excellent blog about regular expressions
// Password validation (at least 8 chars, 1 uppercase, 1 number)
const passwordPattern = /^(?=.*[A-Z])(?=.*\d).{8,}$/;
function validatePassword(password) {
return passwordPattern.test(password);
}
User Authentication
User authentication is verifying a user’s identity before giving them access to their account and everything associated with it. Authentication is useful for user experience. But more importantly, it is a security measure that ensures that sensitive data is accessed only by authorized parties.
User authentication is essential to web security. Without it, user accounts are vulnerable to cyber-attacks. Consider a website without 2-factor authentication. It is easy to hack a user's account on such a website. All an attacker has to do is guess the user's password. That is why it is important to utilize the knowledge factor, possession factor, and inherence factor.
The knowledge factor authentication is based on knowledge that only the user would have. Security questions and passwords are in this category. The possession factor, however, refers to authentication that requires physical devices owned by the user. A physical cryptocurrency wallet is an example here. Finally, consider the inherence factor for authentication. It has to do with biometrics such as fingerprints, facial recognition, etc.
Generally, though, most security on the client is based on the knowledge factor. It is unlikely that a website would request fingerprints for access. Nevertheless, user authentication techniques for the client are based on either of those factors.
Common authentication techniques:
Password-based authentication receives a password from a user in exchange for access. This is the most common form of user authentication/authorization. One issue with this approach is that weak passwords will be easily bypassed.
Multi-factor authentication (MFA) enforces several layers of authentication on users. E.g., in 2-factor authentication, you set a password and also receive a one-time passcode via SMS. The purpose of this extra layer is often to notify you of a potential hack on your account. Mixing the knowledge factor with the physical factor works here. For example, Gmail requires users to log in with a password and confirm the login on a device that they own!
Certificate Base Authority collaborates with a trusted authority to issue a unique certificate. e.g., the Microsoft Authenticator app is a trusted authority. The developer can use it to generate a unique code to authenticate a user. The user would then input the code to gain access.
Token-based authentication generates access tokens that give a user access to certain features. Tokens usually have a scope, i.e., they give restricted access to features. Tokens also expire. One example of this is the Spotify API Oauth sign-in. It allows third-party apps to make changes to users' accounts as long as an access token is part of the API call. First, the user gives the developer access to their account. Then Spotify sends the developer an access token. The developer then uses the token to perform actions within the scope of what the user has agreed to.
// Basic password authentication
function authenticateUser(username, password) {
const user = database.findUser(username);
if (user && user.password === password) {
return true; // Authentication successful
}
return false; // Authentication failed
}
// 2-Factor Authentication with SMS code
function authenticate2FA(username, password, smsCode) {
if (authenticateUser(username, password)) {
if (verifyCode(username, smsCode)) {
return true; // 2FA successful
}
}
return false; // 2FA failed
}
User Authorization
User authorization is the conditional issuance of permissions to different kinds of users of a website. Simply put, authorization determines what privileges different clients have. Authorization filters users based on varying conditions and gives access accordingly. An important mental model for thinking about this is as follows:
- Subject: Who is the user?
- Resource: which object does the user want to access?
- Action: Which actions is the user trying to perform with the resource he has access to?
Consider business enterprise resource management software. For a given business, there are finance, human resources (HR), and product dashboards. Naturally, the head of finance has access to the finance dashboard. The head of HR has access to the HR dashboard, and the head of product uses the product dashboard. Imagine that the HR manager needs some information on his department's budget. We could simply give him/her limited access to the finance dashboard. Many of the tools that you use as a developer already have these features. Figma, Google, and even Jira all give conditional access to different features.
Common user authorization techniques
Some user authorization methods are as follows:
Role-Based Access Control allows access to resources depending on the role of the user. For example, Google Docs has roles for editors, viewers, and commenters. Someone with the role of a commenter cannot access the features of an editor.
Attribute-Based Access Control filters different users based on their attributes. Consider a SAAS website with tiered pricing. Users either have access to premium features or not, depending on whether they have paid or not. One independent publisher on the internet noticed that excessive scrapping was affecting the performance of his website. So he put up a paywall to allow only paid users to access the content. This action improved the website's performance!
Privileged Access Management prevents regular users from accessing sensitive information. An excellent example of this is WordPress. WordPress websites are publicly accessible. Yet only the website administrators can make any changes to them.
// Role-based access control
function authorize(user, resource, action) {
const role = user.role;
const permissions = roles[role];
const isAllowed = permissions.some(p =>
p.resource === resource && p.actions.includes(action)
);
return isAllowed;
}
// Attribute-based access control
function authorizePaidContent(user, resource) {
if (user.subscription === 'paid') {
return true; // Allow paid users
}
return false; // Block non-paid users
}
Data Protection
Data protection is critical to client-side security. Modern web applications are complex. They also handle a lot of sensitive information. It is important to protect data for the following reasons:
- Preventing Data Leakage: Data stored on the client side, such as user preferences, session tokens, and cached data, must be safeguarded to prevent unauthorized access or leakage.
- Compliance Requirements: Adhering to data protection standards and regulations, such as GDPR, HIPAA, or CCPA, is essential to ensure the legal and ethical handling of user data.
- Mitigating Security Risks: Data protection measures reduce the risk of data breaches, identity theft, and other security threats that exploit vulnerabilities in client-side data storage.
Techniques for Data Protection
Encryption: Encrypting sensitive data before storing it on the client side ensures that even if accessed by unauthorized parties, the data remains unreadable without the decryption key. To do this, Use strong encryption algorithms such as AES (Advanced Encryption Standard) for encrypting data at rest and TLS (Transport Layer Security) for encrypting data in transit.
Data Masking and Tokenization: Masking sensitive data elements or tokenizing them into non-sensitive equivalents reduces the exposure of actual data, enhancing privacy and security.
Use tokenization services or libraries to generate and manage tokens for sensitive data fields, such as credit card numbers or personally identifiable information (PII).Regular Security Audits and Updates: Conduct regular security audits and updates of your client-side data protection mechanisms to identify and address vulnerabilities proactively. Stay informed about emerging security threats and best practices in data protection to continually improve your application's security posture.
By implementing these data protection techniques, web developers can enhance the security and privacy of client-side data, thereby fostering user trust and compliance with regulatory requirements.
Secure Communication
Secure communication is pivotal to safeguarding data integrity, confidentiality, and authenticity during transmission between clients and servers. Secure communication is important for the following reason:
- Data Confidentiality: Encryption ensures that sensitive data exchanged between clients and servers remains confidential and unreadable to unauthorized entities.
- Data Integrity: Secure communication protocols, such as HTTPS, prevent data tampering or modification during transmission, maintaining data integrity and trustworthiness.
- Authentication and Identity Verification: Secure communication protocols enable mutual authentication between clients and servers, verifying the identities of both parties to prevent impersonation attacks.
- Protection Against Eavesdropping: Encryption of data in transit mitigates the risk of eavesdropping or interception by malicious actors seeking to capture sensitive information.
Techniques for Secure Communication
-
HTTPS (Hypertext Transfer Protocol Secure):
- Utilize HTTPS to encrypt data exchanged between clients and servers, providing a secure communication channel over the Internet.
- Obtain and install SSL/TLS certificates from trusted certificate authorities to enable HTTPS on your web servers.
-
TLS (Transport Layer Security):
- Implement the latest TLS versions (e.g., TLS 1.2 or TLS 1.3) with strong cipher suites to secure communication channels and protect against known vulnerabilities.
- Configure server-side security settings, such as Perfect Forward Secrecy (PFS), to enhance the resilience of TLS encryption.
-
Certificate-based Authentication:
- Employ certificate-based authentication mechanisms, such as client SSL certificates, to verify the identities of clients and servers during SSL/TLS handshake.
- Maintain a secure certificate management process, including certificate issuance, revocation, and renewal, to prevent certificate-related security incidents.
-
Content Security Policies (CSP):
- Implement CSP headers to define and enforce security policies regarding permitted content sources, mitigating risks associated with XSS attacks and content injection vulnerabilities.
- Specify strict CSP directives, such as 'default-src 'self'', 'script-src 'nonce-hash'', and 'upgrade-insecure-requests', to enhance web application security.
-
Secure WebSockets:
- When using WebSockets for real-time communication, ensure WebSocket connections are secured with SSL/TLS encryption to protect data exchanged between clients and servers.
- Apply WebSocket security best practices, such as rate limiting, origin validation, and message validation, to prevent WebSocket-based attacks and abuse.
-
Secure File Transfers:
- For file uploads or downloads, employ secure protocols such as SFTP (SSH File Transfer Protocol) or HTTPS with multipart form data to encrypt file transfers and prevent unauthorized access.
- Implement server-side file validation and sanitization to mitigate risks associated with malicious file uploads, including malware or script injections.
-
Network Security Measures:
- Deploy network security measures, such as firewalls, intrusion detection/prevention systems (IDS/IPS), and secure VPNs (Virtual Private Networks), to protect against network-based attacks and unauthorized access attempts.
- Monitor network traffic and perform regular security audits to detect and respond to anomalous or suspicious activities affecting secure communication channels.
By adopting these secure communication techniques and best practices, web developers can establish resilient and trustworthy communication channels, ensuring the confidentiality, integrity, and authenticity of data exchanged between clients and servers.
Conclusion
Client security is essential to protecting user data and defending against cyberattacks. Here’s everything we covered in this article:
Input validation protects your website from SQL injections and other malicious input. User authentication and authorization are children of the same parent. Authentication ensures that only the owner or a user account can access it. Authorization creates permissions that limit or allow access to resources within a website. Finally, data protection is useful for securing the data that is stored on the client; while secure communication protects the data that travels between the server and the client.
Top comments (0)