codeql icon indicating copy to clipboard operation
codeql copied to clipboard

Python: Timing attack

Open ahmed-farid-dev opened this issue 3 years ago • 9 comments

A constant-time algorithm should be used for checking the value of info. In other words, the comparison time should not depend on the content of the input, Otherwise, an attacker may be able to implement a timing attacks that may reveal the value of sensitive info

ahmed-farid-dev avatar Jun 27 '22 16:06 ahmed-farid-dev

Hi @tausbn , I'm sorry for the delay. you can feel comfortable to review the PR now, let me know if there is a problem with the query.

ahmed-farid-dev avatar Jul 26 '22 23:07 ahmed-farid-dev

Hi @ahmed-farid-dev, please ensure all your .ql and .qll files are autoformatted, and that test passes (they currently don't). There is also a problem with your .qhelp, since there needs to be one .qhelp file for each .ql query file.

For testing, see this reference: https://codeql.github.com/docs/codeql-for-visual-studio-code/testing-codeql-queries-in-visual-studio-code/

(to perform autoformatting, use the Format Document command in VS Code -- there is an option to do this every time you save your file)

RasmusWL avatar Aug 01 '22 08:08 RasmusWL

@ahmed-farid-dev I triggered CI for your latest commit, but there are still problems running the tests due to compilation errors (as highlighted by my previous comment). Please just let me know once you've solved the problems, then I can take a look at the PR :blush:

RasmusWL avatar Aug 12 '22 08:08 RasmusWL

hi @RasmusWL , you can take a look now.

ahmed-farid-dev avatar Aug 16 '22 11:08 ahmed-farid-dev

Hi @tausbn, Tell me if anything i can do to help the test get passe

ahmed-farid-dev avatar Aug 18 '22 11:08 ahmed-farid-dev

I think the tests should pass now. I'll proceed with the review.

tausbn avatar Aug 19 '22 11:08 tausbn

HI @tausbn , you can run the tests now :+1:

ahmed-farid-dev avatar Sep 05 '22 17:09 ahmed-farid-dev

Hi @tausbn, any update ?

ahmed-farid-dev avatar Sep 12 '22 16:09 ahmed-farid-dev

Hi @tausbn, any update ?

Hi @ahmed-farid-dev. I'm currently waiting for the Security Lab to finish their analysis of the results for your query. As I understand it, they are currently looking at your other timing attack submission (for Java), and as there is considerable overlap in the approaches used in the two PRs, I will wait on submitting my review until that PR has been assessed.

tausbn avatar Sep 12 '22 16:09 tausbn

QHelp previews:

python/ql/src/experimental/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.qhelp

Timing attack against Hash

Timing Attack is based on the leakage of information by studying how long it takes the system to respond to different inputs. it can be circumvented by using a constant-time algorithm for checking the value of Hash, more precisely, the comparison time should not depend on the content of the input. Otherwise the attacker gains information that is indirectly leaked by the application. This information may then be used for malicious purposes.

Recommendation

Two types of countermeasures can be applied against timing attacks. The first one consists in eliminating timing variations whereas the second renders these variations useless for an attacker. The only absolute way to prevent timing attacks is to make the computation strictly constant time, independent of the input. Use hmac.compare_digest() method to securely check the value of Hash. If this method is used, then the calculation time depends only on the length of input byte arrays, and does not depend on the contents of the arrays. Unlike == is a fail fast check, If the first byte is not equal, it will return immediately.

Example

The following example uses == which is a fail fast check for validating a Hash.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :timing attack Against Hash
"""
import hmac
import hashlib

key = "e179017a-62b0-4996-8a38-e91aa9f1"
msg = "Test"

def sign(pre_key, imsg, alg):
    return hmac.new(pre_key, imsg, alg).digest()

def verify(msg, sig):
    return sig == sign(key, msg, hashlib.sha256) #bad

The next example use a safe constant-time algorithm for validating a Hash:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :preventing timing attack Against Hash
"""
import hmac
import hashlib

key = "e179017a-62b0-4996-8a38-e91aa9f1"
msg = "Test"

def sign(pre_key, imsg, alg):
    return hmac.new(pre_key, imsg, alg).digest()

def verify(msg, sig):
    return hmac.compare_digest(sig, sign(key, msg, hashlib.sha256)) #good

References

python/ql/src/experimental/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.qhelp

Timing attack against Hash

Timing Attack is based on the leakage of information by studying how long it takes the system to respond to different inputs. it can be circumvented by using a constant-time algorithm for checking the value of Hash, more precisely, the comparison time should not depend on the content of the input. Otherwise the attacker gains information that is indirectly leaked by the application. This information may then be used for malicious purposes.

Recommendation

Two types of countermeasures can be applied against timing attacks. The first one consists in eliminating timing variations whereas the second renders these variations useless for an attacker. The only absolute way to prevent timing attacks is to make the computation strictly constant time, independent of the input. Use hmac.compare_digest() method to securely check the value of Hash. If this method is used, then the calculation time depends only on the length of input byte arrays, and does not depend on the contents of the arrays. Unlike == is a fail fast check, If the first byte is not equal, it will return immediately.

Example

The following example uses == which is a fail fast check for validating a Hash.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :timing attack Against Hash
"""
import hmac
import hashlib

key = "e179017a-62b0-4996-8a38-e91aa9f1"
msg = "Test"

def sign(pre_key, imsg, alg):
    return hmac.new(pre_key, imsg, alg).digest()

def verify(msg, sig):
    return sig == sign(key, msg, hashlib.sha256) #bad

The next example use a safe constant-time algorithm for validating a Hash:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :preventing timing attack Against Hash
"""
import hmac
import hashlib

key = "e179017a-62b0-4996-8a38-e91aa9f1"
msg = "Test"

def sign(pre_key, imsg, alg):
    return hmac.new(pre_key, imsg, alg).digest()

def verify(msg, sig):
    return hmac.compare_digest(sig, sign(key, msg, hashlib.sha256)) #good

References

python/ql/src/experimental/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.qhelp

Timing attack against header value

A constant-time algorithm should be used for checking the value of sensitive headers. In other words, the comparison time should not depend on the content of the input. Otherwise timing information could be used to infer the header's expected, secret value.

Recommendation

Two types of countermeasures can be applied against timing attacks. The first one consists in eliminating timing variations whereas the second renders these variations useless for an attacker. The only absolute way to prevent timing attacks is to make the computation strictly constant time, independent of the input. Use hmac.compare_digest() method to securely check the secret value. If this method is used, then the calculation time depends only on the length of input byte arrays, and does not depend on the contents of the arrays. Unlike == is a fail fast check, If the first byte is not equal, it will return immediately.

Example

The following example uses == which is a fail fast check for validating the value of sensitive headers.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :preventing timing attack against header value
"""

from flask import Flask
from flask import request

@app.route('/bad')
def bad():
    secret = request.headers.get('X-Auth-Token')    
    if secret == "token":
        raise Exception('bad token')
    return 'bad'

if __name__ == '__main__':
    app.debug = True
    app.run() 

The next example use a safe constant-time algorithm for validating the value of sensitive headers:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :preventing timing attack against header value
"""

from flask import Flask
from flask import request
import hmac

@app.route('/good')
def good():
    secret = request.headers.get('X-Auth-Token')    
    if not hmac.compare_digest(secret, "token"):
        raise Exception('bad token')
    return 'good'

if __name__ == '__main__':
    app.debug = True
    app.run() 

References

python/ql/src/experimental/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.qhelp

Timing attack against secret

Timing Attack is based on the leakage of information of secret parameters by studying how long it takes the system to respond to different inputs. it can be circumvented by using a constant-time algorithm for checking the value of sensitive info, more precisely, the comparison time should not depend on the content of the input. Otherwise the attacker gains information that is indirectly leaked by the application. This information is then used for malicious purposes.

Recommendation

Two types of countermeasures can be applied against timing attacks. The first one consists in eliminating timing variations whereas the second renders these variations useless for an attacker. The only absolute way to prevent timing attacks is to make the computation strictly constant time, independent of the input. Use hmac.compare_digest() method to securely check the value of sensitive info. If this method is used, then the calculation time depends only on the length of input byte arrays, and does not depend on the contents of the arrays. Unlike == is a fail fast check, If the first byte is not equal, it will return immediately.

Example

The following example uses == which is a fail fast check for validating a secret.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Desc   :timing attack against sensitive info
"""

from flask import Flask
from flask import request

@app.route('/bad', methods = ['POST', 'GET'])
def bad():
    if request.method == 'POST':
        password = request.form['pwd']
        return password == "test"
    
if __name__ == '__main__':
    app.debug = True
    app.run() 

The next example use a safe constant-time algorithm for validating a secret:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :preventing timing attack sensitive info
"""
from flask import Flask
from flask import request
import hmac

app = Flask(__name__)

@app.route('/bad', methods = ['POST', 'GET'])
def bad():
    if request.method == 'POST':
        password = request.form['pwd']
        return hmac.compare_digest(password, "1234")
    
if __name__ == '__main__':
    app.debug = True
    app.run() 

References

python/ql/src/experimental/Security/CWE-208/TimingAttackAgainstSensitiveInfo/TimingAttackAgainstSensitiveInfo.qhelp

Timing attack against secret

Timing Attack is based on the leakage of information of secret parameters by studying how long it takes the system to respond to different inputs. it can be circumvented by using a constant-time algorithm for checking the value of sensitive info, more precisely, the comparison time should not depend on the content of the input. Otherwise the attacker gains information that is indirectly leaked by the application. This information is then used for malicious purposes.

Recommendation

Two types of countermeasures can be applied against timing attacks. The first one consists in eliminating timing variations whereas the second renders these variations useless for an attacker. The only absolute way to prevent timing attacks is to make the computation strictly constant time, independent of the input. Use hmac.compare_digest() method to securely check the value of sensitive info. If this method is used, then the calculation time depends only on the length of input byte arrays, and does not depend on the contents of the arrays. Unlike == is a fail fast check, If the first byte is not equal, it will return immediately.

Example

The following example uses == which is a fail fast check for validating a secret.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Desc   :timing attack against sensitive info
"""

from flask import Flask
from flask import request

@app.route('/bad', methods = ['POST', 'GET'])
def bad():
    if request.method == 'POST':
        password = request.form['pwd']
        return password == "test"
    
if __name__ == '__main__':
    app.debug = True
    app.run() 

The next example use a safe constant-time algorithm for validating a secret:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

"""
@Desc   :preventing timing attack sensitive info
"""
from flask import Flask
from flask import request
import hmac

app = Flask(__name__)

@app.route('/bad', methods = ['POST', 'GET'])
def bad():
    if request.method == 'POST':
        password = request.form['pwd']
        return hmac.compare_digest(password, "1234")
    
if __name__ == '__main__':
    app.debug = True
    app.run() 

References

github-actions[bot] avatar Mar 24 '23 14:03 github-actions[bot]