Skip to content

Security: alextanhongpin/evolutionary-architecture

Security

security.md

Security

We can set the user and role for this to log the credentials of the user that accessess it.

$ echo -n app:user:role | md5
$ echo -n "simple text" | shasum -a 256

Expiring JWT Token

Set a version in the jwt token, and set the equivalent version in the server that signs the token. If we ever need to kick all the users out of the server, then we just need to change the version.

Should I tie a JWT token to a specific device (detect by user-agent)

No. https://stackoverflow.com/questions/38992239/json-web-token-make-it-client-specific

Blacklisting JWT

It's not possible to implement actual logout with JWT. From the client side, we can simply remove the JWT token from the localstorage, but cannot prevent user from keeping a copy of it. To ensure that tokens that have been removed cannot be reused, we need to blacklist them.

One way is to store the blacklisted JWT token in Redis, and set the expiry in Redis by computing the time remaining for the token to expire. But this means for every calls that needs the authorization, they need to call Redis to check if the token is still valid or not.

Algorithm for Blacklisting JWT

Blacklisting token by storing the jwt token not only takes a lot of space, this would probably not work if the user login from multiple devices, since we will only logout from one device, there's no way to know the tokens that the user logged in with. One solution could be to store the jwt token in the database when they are created, but this defeats the purpose of the jwt token (suppose to be stateless).

A better solution would be to take into consideration what is stored in the jwt token, mainly the issued_at and subject (user id). Since all the tokens generated will have that attributes, it could be potentially used to invalidate multiple tokens. Consider the following scenario:

User is logged in two devices:

  • mobile, issued 3 days ago
  • desktop, issued yesterday

The JWT token is set to expire in 7 days (example only, it should be long living). When the user logout, we want to ensure those tokens can no longer be used. This is the algorithm:

  • When the user logout, store the logout_at in the db. Why not the last_login_at? Because if we attempt to use the last login date to compare against the jwt token's issued_at date, it will not work when the user login multiple times in different devices. Every login will override the previous last login at date. The logout_at date however is one time only, we can always use it to compare it against all the JWT's issued_at date. If the date is less than the logout_at date, then it is deemed invalid. This will invalidate all the tokens stored on the client side when they make a requests against any resource.
  • Store the same logout_at date together with the user_id in redis. Set the key to expire with the current logout_at + jwt expire duration. When the entry expire, we no longer need to check if there are blacklisted tokens (tokens that has not expired, but we define them as expired since the issued date is less than the logout date), since by now all the other token would have expired (original jwt expiry date).
  • Now, whenever the user make a request with an old/new jwt token, get the user id. If the redis has the user id available, go to the next step, else just validate as usual.
  • The user id is available, get the last logout_at date and compare against the issued_at date. If it is less, it means the token has been blacklisted. Any new token will pass, since the issued at date is always greater than the last logout date.
  • We could just store the data in memory, but it will only work on a single instance, it will not scale for distributed system. Also, on every restart, we need to find users with the logout_at + jwt expire duration less than now, and set it in memory. The same goes if the redis server restarts.

With that, we have accomplish four things:

  • minimize storage for redis (we only store the user_id and last logout at, and set it to expire from the last logout at + jwt expire duration, instead of storing all the jwts). The entry in redis will also be persisted with max last logout at and the jwt duration). Also, we are only storing one entry versus N JWT tokens generated by the client.
  • minimize lookup. We still need to make a lookup to redis on every call, but the logic is only performed (comparing the issued at and last logout at) when the entry exists. It should be faster than performing a db lookup, and it works on multiple services.
  • customize message. If the entry exists in redis, and the token is indeed issued before the last logout, we can return a message indicating that the session expired. This would have differentiate it from the invalid jwt token/jwt expired token.

Optimization. We previously set the expired at for the redis entry to be equal the last login at + jwt duration. If you notice, the duration will actually be very short. We would still have to check the token blacklist status for the lifetime of the jwt token. One way to optimized it is to set the last login at date too in the database. It will be updated with every login and will always hold the latest login at date. When we logout the user, create the entry at redis with the last login at, last logout at, user id and set it to expire with the last login at + jwt duration. If the last login at is 4 days, and the jwt duration is 1 week, then the blacklisted entry will only be valid for the remaining 3 days.

Custom Bearer

How to implement custom bearer

Basic Authentication

For ops login.

Passwords in environment variable

A common mistake is to store plaintext user credentials in the environment variables. We need to distinguish the types of environment variables. It can usually be categorized as config or secret.

To pass in the credentials through environment variable, hash the username:password using SHA256 (or similar hashing that are strong enough). To compare, hash the input username:password credentials with those set in the environment variable.

Encryption

What possible encryption methods are available...

Replay attack

  • timestamp event/requests
  • Events without timestamp is invalid
  • If the event is out of time(less than 5 minutes/validity period ago, or from the future), it is invalid
  • If the action to be taken is only valid for a certain period, set a due date. Action must be carried out within that period
  • Set a date on the entity to be updated, for the next change, check if the ts is greater than the previous timestamp, if yes, only update it

Performance and security as a feature

Business Login in JWT

JWT should not contain business logic - if the token holds claims that are dynamic, any change to the data requires the old token to be invalidated/blacklisted, and the client has to fetch a new token with the new claims.

JWT Token is best used for authentication (who the caller is), even when it can perform authorization (what the caller can do) through claims.

Setting Roles in JWT

JWT token is like a passport - it represents the identity of the user at the time the token is generated, until it expired. Thus, we carry along an assumption that the claims set in the JWT are static and should not change frequently. Roles however can be dynamic. Changing the roles on the server side will still leave the existing JWT token with the old roles.

This can have some serious security consideration, imagine giving an admin access to the token. Even when the token is short-lived, the amount of harm that can be done is immeasuarable. Some possible solution (and problems they introduce):

  • maintaining a separate blacklist table, which now makes the application stateful. Also, the blacklist table needs to be stored in a distributed cache to avoid load-balancing issue or role-checking on different application for the same user.
  • check the db everytime a requests is send to validate the role (either an independent call, or in the statement query).

Fuzzy testing (?) with strings

https://github.com/minimaxir/big-list-of-naughty-strings

Anomaly Detection for requests

In order to accomplish this, we need to detect the usage pattern for each users on the different endpoints. Endpoints such as login will normally be rarely called, hence having a increase request over a short time frame can be suspicious.

  • how to detect low requests (below the rate limit) abuse?
  • how to detect scraping (if they call it at fixed interval or non-fixed interval)
  • how to perform time-series anomaly detection?

Fraud detection

This may be different than anomaly detection, that it detects the attempts of creating fake resources (accounts, orders) and testing the waters.

Abuse and DDOS

Abuse and DDOS can be prevented by adding rate-limit to the system, and blacklisting the IP address that exceeded the rate limit frequently. There are active and passive systems that detects the abuse.

  • active. State is hold in application. The ip is immediately added to blacklist once the threshold is exceeded, and the user is banned.
  • passive. Through log analysis. The request logs are sent to a system to be analysed, and the response is then feed back to a distributed storage (redis etc) and refreshed by the application (or load balancers), which then blacklists the ip.

Login Jail Gate

https://github.com/alextanhongpin/js-learn/blob/master/counter.md

There are several confusion regarding throttling and rate limiting.

  • Throttling is meant to control the usage at a defined time window, e.g. User can only make 100 requests per day.
  • Rate limit defines the rate at which an API can be consumed, e.g. User can only make 1 request per second, that is 86,4000 requests per day. But if we apply the throttle, then the user can only call up to 100 requests per day.

STRIDE

  • Spoofing: Authenticity. Using another user credentials without their knowledge.
  • Tampering: Integrity. Tampering of data such as overriding important data or deleting it.
  • Repudiation: Non-repudiability. Attackers hide the actions that they have performed, for instance by erasing them from the logs.
  • Information disclosure: Confidentiality. Data breaches.
  • Denial of Service: Availablity. Prevent regular users from accessing the system, through DDOS etc.
  • Elevation of Privilege: Authorization. Attackers attempt to gain higher privileges.

https://en.wikipedia.org/wiki/STRIDE_(security) https://www.futurelearn.com/courses/cyber-security/0/steps/19631 https://dev.to/petermbenjamin/demystifying-stride-threat-models-230m

Kerkchoffs Principle

https://en.wikipedia.org/wiki/Kerckhoffs%27s_principle

XSS Protection

TODO: Check if the app renders html/script in json response.

ZAP

Zed-Attack-Proxy. Try to implement a basic dockerized version, and add it into the pipeline.

CSP

Short for Content-Security-Policy. Look into how to implement a basic policy:

w.Header().Add("Content-Security-Policy", "default-src 'self'")

CSRF

if !checkCSRFHeader(r.Header.Get("X-CSRF-TOKEN")) {
    w.WriteHeader(http.StatusNotAcceptable)
    w.Write([]byte("Invalid CSRF Token"))
}

Cookie

Set the option SameSite=strict.

Clickjacking

w.Header().Add("X-Frame-Options", "SAMEORIGIN")

Basic Auth

if r.Header.Get("Authorization")[0:5] != "Basic" {
    // Error
}

token = r.Header.Get("Authorization")[7:]
tokenDecoded, err := base64.StdEncoding.DecodeString(token)
username := tokenDecoded[0:strings.Index(":")]
password := tokenDecoded[strings.Index(":") + 1:]
w.Header().Set("WWW-Authenticate", `Basic-Realm=""`)

NSP

Checkout node-security platform

Ops Access

Add a cron job to randomize the credentials daily and email/slack it to the user.

Client Side

When logging in, store the token in the application state rather than local storage. When user closes the application, store it in the local storage.

The next time the user login, get the token from the localStorage, store it in the application state and delete it from the localStorage.

Allow passwords to auto-rotate by randomly generating a unique password

# Generate a hashed credentials
echo -n "username:password" | shasum -a 256

# Pass this in as an environment variable CREDENTIALS

# In the application, compare the hashed username:password with the credentials

Prevent scraping through pagination token

Numeric pagination is easy to scrape ?limit=9999&offset=1. Find a way to create a pagination token that is hard to scrape.

Also, do not expose id of resources to the frontend. That includes pages that displays a single item and so on e.g. books/:id. Rather, use slug instead as identifier.

NOTE: I probably misunderstood why some apis base64 encode the token for pagination. Apparently for large scale websites, the integer id cannot be deserialized as int64 for javascript, hence it is base64 encoded as string. It does not add any security enhancement to the api.

Maching Learning for security

Finding outliers from the data, or probably datapoints with perfect correlation (think scraping at the fixed interval).

W3C Web Authentication

https://www.w3.org/TR/webauthn/

AES-GCM vs AES-CBC for encryption

https://security.stackexchange.com/questions/184305/why-would-i-ever-use-aes-256-cbc-if-aes-256-gcm-is-more-secure

Fire Alarm

Inspired by OWASP AppSensor. Implement something like a fire alarm trigger to disable certain parts of the application when there are possible attackers. I've been wondering how to make full use of logs, (context logs with correlation id, open tracing, open census), just storing them is not enough. There need to be some action that needs to be done. Also, when an application is experiencing high traffic, it should not affect the whole instance - only the pipeline that is affected should be regulated.

Do a pipeline-style architecture that can be dropped when attacked. Create a log analysis mechanism too.

Apply Modular Crypt format for Argon2

https://passlib.readthedocs.io/en/stable/modular_crypt_format.html deprecated in favor of https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md

How to block ip address?

https://husobee.github.io/golang/ip-address/2015/12/17/remote-ip-go.html

Designing a proper security pipeline.

Test entropy of random numbers with NIST statistical test suite

Questions

  • how to handle anonymous session/best practices and why do we need to do it (prevent attacks, fingerprint user)
  • is sessionid using uuid secure? also look at the mysql uuid to binary to see how we can save bytes
  • how to block ip address, and better way to fingerprint user
  • how does redis ttl works (solved, can create a naive implementation using golang)
  • NIST statistical test suite to test random number
  • how to secure ajax
  • TOCTOU (time of check, time of use race condition)
  • how to design a proper security pipeline in CI/CD (git pre-commit check, zed attack proxy docker)
  • handling caching for client side. One way is to return a version for each api response. When calling the first api call, check the version and see if the data needs to be prefetched.
  • reducing string storage size with 16bits http://www.kinematicsoup.com/news/2016/9/6/data-compression-bit-packing-101

Api Designs

  • throttling, backoff, circuit breaker and rate limit
  • rate limit by ip (throttle individual requests)
  • rate limit by ip + path (throttle individual usage for specific endpoint)
  • circuit breaker for error? when a user type in wrong password three times
  • request id library (make it modular)
  • caching json response?
  • ttl map for golang (similar like redis EXP)

JWT

Jwt why different audience for mobile Tracking for different devices

  • Logout all feature by changing the main secret
  • Logout all by checking the issued date less than logout date
  • we can handle logout from different devices with the same trick, but this requires an external distributed cache
  • how to handle sessions from different devices? when the user first request the token, store all the necessary data (user agent, location etc), and every other time the user calls the endpoint with the token, track the location and check if it is possible). We can user haversine distance to calculate the user’s velocity and see if it’s possible. Walking distance, commuting, driving, cycling all has an average velocity. If we can compare the outliers, we can identify suspicious activities)
  • the same concept is used for credit card, called the card velocity.
  • since we can get the unique id of the device when they logged in, we can tie the usage. This will require a lot of checking though. We can use complex event processing to monitor the changes. stream the data to a pipeline, and compare the location (if null, how should it be handled, if user did not provide the location?)
  • using Subject instead of custom claims
  • setting audience and issuer effectively
  • exclude dynamic roles in the jwt token
  • why use session instead
  • should we have refresh token for applications?

Authorization

  • how does authorization works for offline application?
  • how to split the application into hybrid offline/online solution? read only data can always be offline. If we want to create data etc, we can perform it locally first, then sync the data later when we are online(?) will this cause a hotspot issue, when all offline devices went online at the same time.
  • how to ensure the files created offline are batched before synced online (especially when there are plenty of files)
  • the idea of putting things offline is to save the network calls to the server, hence reducing server load and making the application more responsive.
  • syncing server like dropbox is what we need. But how do we design it? We can queue the requests on the client side and then fire them when they are back online. We need to ensure the calls are not rapid to prevent own ddos. Another alternative is to set a rule that only online clients can upload content.

References

For Throttling and Rate Limiting

This is the iterinary taken from a security course

Implement all of this

KEY LEARNING OBJECTIVES

  • API and microservices security architecture. 

  • How to create APIs that are easy to use securely and hard to use insecurely. 

  • What are the techniques and tools to design, test and attack APIs and microservices. 

  • Understanding the intricate and minute details of authentication and authorisation frameworks and technologies. 

  • Learning how to effectively solve the problem of credential storage. 

  • Attack and defend against injection vulnerabilities e.g. Template Injection, SQL injection, NoSQL injection (MongoDB, GraphQL, etc.). 

  • Attack and defend against API and serverless oriented vulnerabilities e.g. serialisation, JSON injection, pickling, Edge Side Includes, Serverless Event Injection, etc. 

  • Learn AJAX and REST security best practices. 

  • Know when to use signing, when to use encryption, and when to use both. 

  • Implement applied, battle-tested secure cryptography. 

  • Obtain actionable knowledge and experience in using secure tokens, cookies, keys and tickets for authentication and authorisation.

  • Attack insecure implementations of session management, input validation, output encoding and loosely coupled components. 

  • Implement secure communication channels with API consumers e.g. web browsers and mobile apps. 

  • Mitigate and defend against XSS, CSRF, JSONP and CORS security weakness in APIs. 

  • Implement secure web socket channels and defend against Cross-Site WebSocket Hijacking. 

  • Implement and attack multi-factor authentication for APIs. 

  • Learn and understand cache security and what threats and vulnerabilities can arise out of insecure caching methods and configurations. 

  • Handle files securely by allowing only authorised downloads even in segmented microservice architectures. 
   AGENDA   Day 1
  • Introduction to the Modern Web
    • Differences between modern and conventional web technologies.  

    • Microservices and APIs. 

    • Cloud-native apps and technologies. 

    • Containers and orchestration. 

    • Serverless apps. 

    • Security in this new world. 

    • Setting up local and cloud environments for the class. 

  • Security Architecture for APIs
    • Security of API consumers (Web, Mobile, Microservices, other APIs).  

    • Types of threats for APIs.

    • Serverside attacks against API implementations (injection attacks, data exposure attacks, etc.). 

    • 3rd-party attacks against APIs (authentication weaknesses, cache attacks, etc.).

    • Clientside attacks against API consumers (Confused Deputy attacks, data exposure, authorisation abuse, ID and token hijacking). 

    • Attacks against API infrastructures. 

    • Designing and implementing defensible APIs and infrastructures. 

    • Logging and Monitoring for Serverless. 

  • Data and File Attacks Against APIs and Clients 
    • Attacking and Securing AWS S3 buckets. 

    • Insecure Direct File or Object Access (IDOR) attacks. 

    • Securing file downloads with AWS Signed URLs and Signed Cookies. 

    • Securing file downloads using X-Sendfile and X-Accel-Redirect.

    • Securing file downloads using UUIDs and one-time tokens. 

    • 3rd-party threats against file downloads (caching, URL shorteners, CDNs). 

    • File upload security (path traversal attacks, file inclusion, file type confusion, safe bucket uploads with Presigned URLs, etc.)

  • Injection Attacks Against APIs and Clients 
    • SQL and NoSQL injection attacks. 

    • Template injection attacks. 

    • Object manipulation attacks (Serialisation, Pickling and Eval attacks). 

    • GraphQL security. 

    • XXE attacks. 

    • XSS. 

    • Serverless Event Injection. 

    • Edge Side Include Injection. 

    • Serverside Request Forgery.

  • Cache Security
    • Cache security concerns and configurations in API. 

    • Knowing waht to cache and what not to cache. 

    • Cache attacks: Edge Side Include Injection, Cache Poisoning. 

    • Secure configuration of caching proxies. 

    • Redis and Memcached security. 
   Day 2
  • HTTP Security
    • Same Origin Policy (SOP)
      • Exceptions to SOP 

      • JSONP Security

    • HTTP Atttacks
      • CORS
        • What is CORS

        • Types of CORS requests

        • Securing CORS access

      • CSRF
        • What is CSRF?

        • Attacking and defending against CSRF

        • CSRF attacks on REST APIs

        • CSRF and JWT attacks

        • Using CORS Credentials and Origins checks to protect from CSRF

    • HTTP Security Headers 
      • CSP

      • X-Frame-Options

      • XSS Protection

      • Key Pinning

      • SSL Enforcement Headers

    • Web Socket Security
      • Cross-Site WebSocket Hijacking (CSWSH)

      • Web Socket Origin Checks

      • Web Socket SOP Bypass

      • Web Socket Cryptography

      • Web Socket in the Local Host

      • Web Sockets and CSRF Attacks

      • Cookie Auth v. Local Storage (Token) Auth in Web Sockets

  • Token Security
    • Using Tokens for Authentication and Authorisation 

    • JSON Web Tokens (JWT) and JSON Web Signature (JWS) Security\
      • Security weaknesses in stateless and stateful tokens

      • Insecure token invalidation 

      • Handling stateless JWT tokens

      • Insecure signing and encryption of tokens

      • Stealing tokens via XSS

    • Mapping Tokens to Users and Devices

    • Double Wrapping JWT

    • Stateful v. Stateless Authentication

  • Authentication and Authorisation in APIs
    • OAuth
      • Bearer Tokens, Access Tokens, Refresh Tokens, Scopes, Authorisation Grants

      • Implementing OAuth in Web and Mobile Apps 

      • OAuth Vulnerabilities

      • Security OAuth

    • Session Management and Privileges
      • Secure session management between client and server

      • Secure Login, Logout, Password Reset and Session Lifetime and Invalidation

      • Authorisation and Privilege Management 

      • IDOR, session hijacking and privilege escalation attacks

    • Multifactor Authentication  (MFA)
      • MFA types (TOTP, SMS, U2F)

      • MFA practical implementations (secure enrollment, backup codes, user support)

      • Push notifications as MFA

  • Credential Handling and Storage 
    • Credential storage in apps (Local Storage, Apple Keychain and Secure Enclave, Android KeyStore)

    • Credential storage for APIs
      • Password Hashing

      • HSMs

      • Hashicorp Vault

      • AWS Secrets Manager

    • Checking for compromised credentials using HIBP

    • Secrets API in Kubernetes, Docker Swarm, Mesosphere

  • Cryptography 
    • Secure SSL/TLS Configuration (Cipher suites, Pinning, PFS, Key and Certificate Management). 

    • Applied cryptography for secret storage and transmission. 

    • Securely applying digital signatures. 

    • Secure password storage and handling. 

    • Applied cryptography using Libsodium, BouncyCastle. 

  • Rate Limiting and Bot Control
    • Implementing rate limiting and bot control. 

    • Catching and blocking bad bots.

    • Managing bot control and CAPTCHAs in APIs and mobile. 


Refresh token

Option 1: The worst way to implement refresh token

  • User pass in the old access token, and receives a new access token. This implementation is highly insecure and allows anyone that has access to one of your access token to obtain a new access token…forever.

Option 2: Returns a refresh token and access token when the user logs in.

  • The refresh token is used to obtain a new access token.
  • If the attacker manages to retrieve the refresh token, they can also renew the access token forever.
  • User may choose to revoke the refresh token.
  • This implementation still is not secure

Option 3: Similar as option 2, but a new refresh token is returned with the access token when the user posts to the refresh token endpoint.

  • This assumes that the refresh token is stored in the user table.
  • Every time the user calls the refresh token, the user table column refresh token will be replaced with a new one.
  • This does not deal with multiple devices. Consider the following scenario:
    • User logs in device A. User obtains a refresh token.
    • User logs in device B. User obtains the same refresh token.
    • Token expires on device A, now user posts to refresh token and receive a new refresh token.
    • Token on device B will never be able to expire.
  • Concurrency issues when user logs in on multiple devices.

Option 4:

Summary:

Using a single refresh token?

  • Logging out from a device will remove the refresh token capability from all device. What’s worse if the user did not log out of the device, then the refresh token will be there permanently. Also, logging in again from multiple devices will override the previous refresh token.

Splitting the mobile and web authentication

  • Web SPA should not require a refresh token. Only mobile. If we want to have remember me for web, then use the secure cookie. So a table that stores the refresh token and device id pair should be created. (And maybe user id pair)
  • Every new login will create a new refresh token (not logout, since it can be easily forgotten, or maybe the refresh did not make it in time, and the user login without logging out and not clearing the old refresh token)

The very secure implementation is to issue a new refresh token and invalidate the old one each time. But this makes troubles with concurrent calls (e.g. a multi threaded apps)

Multiple OAuth Refresh Token Rolling for the Same Client A client with a single resource owner?s credentials from multiple devices is not working. It has been observed that the Refresh Token issued to one device gets invalidated if a request for the same access token or a refresh token is sent from another device. Roll Refresh Token Values: When selected, the OAuth Authorization Server(AS) generates a new refresh token value when a new access token is obtained.

Secure in memory

https://github.com/awnumar/memguard

Secrets with Sops

https://github.com/mozilla/sops

https://github.com/toniblyx/prowler#requirements-and-installation

There aren’t any published security advisories