Closed iamstarkov closed 5 years ago
see more about "hash vs checksum" https://security.stackexchange.com/questions/194600/checksum-vs-hash-differences-and-similarities/194602#194602
also about cryptographic checksums as in "data integrity" https://www.securitydrops.com/data-integrity/
its not secure enough to use general hash or checksum function, its better to generate signed checksum where signature is known only to a oauth client
maybe HMAC is an overkill. it should be enough to use cryptographic hash function over session and some secret
crypto.createHash('sha256').update(some).digest('hex')
also maybe take user-agent or some user-relevant bits of data into consideration
uuid for session perhaps https://en.wikipedia.org/wiki/Universally_unique_identifier
nay, HMACs are easy and don't require set of public && private keys
crypto.createHmac('sha256', 'secret').update('to be signed').digest('hex')
another great article on oauth2 vulnerabilities https://dhavalkapil.com/blogs/Attacking-the-OAuth-Protocol/
for the oauth2 "authorization" server part http://blog.intothesymmetry.com/2015/04/open-redirect-in-rfc6749-aka-oauth-20.html
like what I was saying https://security.stackexchange.com/a/138923/26493:
When deciding how to implement this, one suggestion is to use a private key together with some easily verifiable variables, for example, client ID and a session cookie, to compute a hashed value. This will result in a byte value that will be infeasibility difficult to guess without the private key. After computing such an HMAC, base-64 encode it and pass it to the OAuth server as state parameter. Another suggestion is to hash the current date and time. This requires your application to save the time of transmission in order to verify it or to allow a sliding period of validity (e.g., using TOTP).
also maybe take user-agent or some user-relevant bits of data into consideration
user agent isnt enough. it probably should be full user agent fingerprint
for fingerprinting we can't trust client user agents. but we can use server side information such as: useragent, acceptHeaders, geoip. (reference https://github.com/yusukeshibata/express-fingerprint)
offtopic uuid/guid https://stackoverflow.com/q/105034/1057730
fingerprinting geoip:
both include async and it is responsible for
another difference description:
geoip-lite is fairly light already, boasting 6 microsecond lookups for IPv4 addresses, and 30 microsecond lookups for IPv6 on a Macbook Pro. However, it ships over 60MB of data for handling city/region names, and thus introduces significant memory overhead. If all you want is country data, and not city/regions, then that's a lot of RAM for unused functionality.
Instead, geoip-ultralight includes under 2MB of data, and has negligible memory consumption. If all you need is to identify countries, this will work perfectly with your Digital Ocean or AWS micro instances. —geoip-ultralite's REDME "why" section
geoip-lite deployed on Now v1:
alright, geoip is complicated, lets postpone it until this hits the now v2 https://spectrum.chat/zeit/now/geoip-information~ac41b4b6-4db3-40d3-a79f-a4435448be46?m=MTU1NjgzNjYwNzQ3MQ==
or until there are even lighter (ram/size/cold start) alternatives
actually there is already simple, fast and serverless ready geoip alternative:
var geolite2 = require('geolite2');
var maxmind = require('maxmind');
var ip = "80.212.72.183";
Promise.all([
geolite2.paths.asn,
geolite2.paths.country,
geolite2.paths.city
].map(x => maxmind.open(x)))
.then(xs => (ip) => xs.map(x => x.get(ip)))
.then(geoip => geoip(ip))
.then(x => JSON.stringify(x, null, 2))
.then(console.log, console.error)
/*
[
{
"autonomous_system_number": 2119,
"autonomous_system_organization": "Telenor Norge AS"
},
{
"continent": {
"code": "EU",
"geoname_id": 6255148,
"names": {
"de": "Europa",
"en": "Europe",
"es": "Europa",
"fr": "Europe",
"ja": "ヨーロッパ",
"pt-BR": "Europa",
"ru": "Европа",
"zh-CN": "欧洲"
}
},
"country": {
"geoname_id": 3144096,
"iso_code": "NO",
"names": {
"de": "Norwegen",
"en": "Norway",
"es": "Noruega",
"fr": "Norvège",
"ja": "ノルウェー王国",
"pt-BR": "Noruega",
"ru": "Норвегия",
"zh-CN": "挪威"
}
},
"registered_country": {
"geoname_id": 3144096,
"iso_code": "NO",
"names": {
"de": "Norwegen",
"en": "Norway",
"es": "Noruega",
"fr": "Norvège",
"ja": "ノルウェー王国",
"pt-BR": "Noruega",
"ru": "Норвегия",
"zh-CN": "挪威"
}
}
},
{
"city": {
"geoname_id": 3162306,
"names": {
"en": "Austmarka"
}
},
"continent": {
"code": "EU",
"geoname_id": 6255148,
"names": {
"de": "Europa",
"en": "Europe",
"es": "Europa",
"fr": "Europe",
"ja": "ヨーロッパ",
"pt-BR": "Europa",
"ru": "Европа",
"zh-CN": "欧洲"
}
},
"country": {
"geoname_id": 3144096,
"iso_code": "NO",
"names": {
"de": "Norwegen",
"en": "Norway",
"es": "Noruega",
"fr": "Norvège",
"ja": "ノルウェー王国",
"pt-BR": "Noruega",
"ru": "Норвегия",
"zh-CN": "挪威"
}
},
"location": {
"accuracy_radius": 20,
"latitude": 60.1003,
"longitude": 12.3213,
"time_zone": "Europe/Oslo"
},
"postal": {
"code": "2224"
},
"registered_country": {
"geoname_id": 3144096,
"iso_code": "NO",
"names": {
"de": "Norwegen",
"en": "Norway",
"es": "Noruega",
"fr": "Norvège",
"ja": "ノルウェー王国",
"pt-BR": "Noruega",
"ru": "Норвегия",
"zh-CN": "挪威"
}
},
"subdivisions": [
{
"geoname_id": 3153403,
"iso_code": "04",
"names": {
"de": "Hedmark",
"en": "Hedmark",
"fr": "Hedmark"
}
}
]
}
]
*/
but good news, you dont need to geoip to fingerprint, because geoip is derivative from ip and thus ip itself as good as geoip data for fingerprinting
basically xsrf check can be streamlined to two checks: fingerprint and session checksums
see https://security.stackexchange.com/questions/20187/oauth2-cross-site-request-forgery-and-state-parameter