Do you have it ? Really ?

What we are looking for the the probability of a person having Corona given a positive test and the test is 90% accurate.

For brevity:

A = have Corona
B = have positive test

P(A) = 0,01 – base rate of contagion in the population. And by implication P(not-A) = 0,99

Test is 90% accurate, and let us further suppose that this is both the sensitivity and the specificity. Where sensitivity is about the absence of false negatives – are you finding it all ? – the proportion of actual positives that are correctly identified as such. And Specificity is about the absence of false positives – are you detecting something else ? – the proportion of actual negatives that are correctly identified as such. Ideally both should be high, but typically one will have to be traded off against the other in any real test. Both being 90% is unrealisitc.

For short P(B|A) = 0.9 and P(not-B | not-A) = 0.9

From this we use the fact that conditional probabilities add up to 1

i.e. P ( B|A ) + P(not-B|A) = 1

and get P(not-B | A) = 0.1 and P( B | not-A) = 0.1

Bayes’ Theorem stipulate P(A|B) = P(B|A) * P(A) / P(B)

Where P(B) = P(B,A) + P(B,not-A) = P(B|A) * P(A) + P(B | not-A) * P(not-A)

Putting in the numbers from above:

P(A|B) = ( 0,9 * 0,01) / ( 0,9 * 0,01 + 0,1 * 0,99) = 0,009 / ( 0,009 + 0,099) ~ 10%

In plan language: The probability of actually having the Corona given a positive test with a 90% accuracy, is only about 10%

 

Let’s recast: what is the chance of not having Corona given the test say you don’t. In other words: how reliable is the all-clear ?


For brevity: What is P ( not-A | not-B) ?

Bayes’ says P(A|B) = P(B|A) * P(A) / P(B)

which for this purpose becomes:

P(not-A| not-B) = P(not-B| not-A) * P(not-A) / P(not-B)

Where P(not-B) = P(not-B, not-A) + P(not-B, A) = P(not-B| not-A) * P(not-A) + P(not-B | A) * P(A)


All of these numbers we have


P(not-A| not-B) = 0,9 * 0,99 / ( 0,9 * 0,99 + 0,1 * 0,01 ) ~ 99,9%


Which is rather impressive. The all-clear really is all-clear. No means no.

Business and reuptational damage from shoddy security pratices at subcontractors. (Norwegian)

I en tid har jeg hatt Telenor Bedrift som mobil leverandør. Men nå har jeg sluttet med det.

Grunnet en heller uklar fakturerings model ble noen av fakturaene fra Telenor avvist for å overstige beløps grensen. Og gikk videre til inkasso. So far, so good. Her ble det interessant. Inkasso firmaet var for meg en helt ukjent firma, Gothia Group, GG. Som sendte en epost med henstilling å betale til KTO nr og KID nummer. De hevdet å agere på vegne av Telenor (merk: ikke «Telenor Bedrift», som jeg har mitt kundeforhold hos). Gitt at en betydelig andel av Norges befolkning har et kunde forhold til Telenor er en slik generisk påstand en ganske god start på et masse-phishing angrep.

Eposten inneholdt heller lite (intet) som forutsatte detaljert kjennskap til kunde forholdet hos Telenor: Ikke opprinnelig faktura nummer eller kunde nummer. Dette ble senere fulgt opp med en oppringning som likeledes var blottet for spesifikk informasjon. Stemmen på telefonen hadde ikke noen tydelig russisk aksent men ellers kunne alt sammen vært generert i en russisk hacker fabrikk. Men gitt av en del call-senter oppgaver er flyttet ut av landet, er ikke en aksent umiddelbart mistenkelig heller. Mangel på spesifikk informasjon derimot er det.

Etter å ha sjekket opp mailen med Telenor gikk jeg inn på den i eposten oppgitte nettsiden.

Starten var mindre enn tillitts vekkedne. GG sine nettsider har ikke sine digitale sertifikater satt opp på en måte som må anses som minste kravet til en virksomhet som driver med penger.

Spesifikt: de benytter Let’s Encrypt Authority X3 som CA for sertifikatet på www.gothiagroup.com. Dette er IKKE en forsvarlig utsteder av digital sertifikater for formålet å identifisere organisasjoners nettsteder. Noe Let’s Encrypt selv heller ikke påstår.

Om penger er involvert er det ikke urimelig at organisasjonen bak nettstedet faktisk identifiserer seg overfor brukerens nettleser.

Men i det minste følger GG godpraksis i at kunden må logg seg inn for å finne korrekt betalings informasjon: En epost kan som kjent komme fra hvor som helst. Den sikkre informasjonen er den kunden selv finner frem til.

Men dette gjelder ikke for Telenor Bedrifts kunder. Den eneste innloggings mekanismen GG har er BankID. Og det virker som de ikke har noen integrasjon som gjøre at de kan koble den personlige innloggingen i BankID med en organisasjon. Så bedrifts kunder kan ikke logge seg inn hos GG for å hente betalings detaljer. De må få dette på epost, etter oppfordring. Eposter som ikke inneholder noen informasjon som kobler kravet til opprinnelig faktura fra Telenor Bedrift. Intet i den er hentet fra Telenor eller er av en slik art at ikke hvem som helst vet det. En russisk «troll farm» ville kunne sendt den eksakt samme eposten.

Så Telenor benytter Gothia Group som ikke kan håndtere bedrifts kunder, for sine bedrifts kunder.

Jeg er ikke lengre en kunde av Telenor Bedrift.

Secrecy and IP – There is public, there is private and there is secret.

If you ask a networking person what a private (IP-)address is, you get one answer: An IP address which is not routable on the internet. There are some IP ranges which have been set aside for use in private networks and won’t work on the internet. For this reason they are sometimes referred to as “non-routable addresses”. Which is why they tend to be used in movies. Type them into your browser and nothing happens. Unless you are in a local network which have routes for them. Emphasis on local. Addresses that start with “10.” and “192.168.” are the most commonly used, and there are a few others as well. Architects tend to think a private address is one that you own.

But what is a public IP address ? That very much depends on who you ask. Network people will say it is it is an address which in not private. An IT architect will say it is an address which is accessible from outside your network. Security would say one which the public can access.

In some sense they are all correct, and that is why the issue is so confused. Because over all of this reigns security. And more particularly secrecy. There are far too many in the IT business who equate security and secrecy. To be sure the two are not opposing concepts for the most part but they intersect only intermittently – and not often. Some think IP security is mainly about secrecy. If the enemy does not know an address, he can’t attack it.

Ah, would that that were so. This is why the difference between public and private is so important. If an architect thinks that a public address is one that other people know about and a private address is one that is secret, the architect might want to keep the address information secret. Only distributed in secure communication; kept in password protected files and in secure document stores etc.

But how secret can an externally accessible IP address really be.

It is illustrative to think in term of physical addresses: A person lives on a secure address. But the house is still there; Numbered sequentially as you like; and the street is public. Anyone can drive to the house at any time. How secure is that? Let’s further suppose that those looking for the occupant of the secure address know that the house has been provided by a company that owns a particular street (public IP range discoverable in DNS). It is a fair guess that the right house is on that street. What does that do to security? If the house is a fortress, it doesn’t matter. But if you base your house security on it being undiscoverable, nothing good.

NAT-ing does nothing useful here. It is like having all your mail sent to the post office and have the post office forward it to your house. Someone can still mail you a remotely detonated bomb (malware). The post office will forward it just the same. (wait a day; trigger it; look for smoke; and you have the right house)

But there is another way: A private road (non-routable/private addresses) cut off from the public road system; you have to be authorized and be lifted in. That is a secure address. Not a full replacement for security at the address of course – you still lock the doors – but the address information is secure as in scanning will not discover it. No looking inside mailboxes on a street you can’t get to.

How to achieve this happy state of affairs. Enter the muddle.

Virtual Private Networks. With “private” here referring both to private addresses as defined above (non-routable) and as in you own it. VPNs are sometimes referred to as encrypted tunnels. Typically based on IPSec but there are other possibilities. Any IP address can be used in a VPN but using a VPN you can have your non-routable “10-dot” address be accessible from anywhere, even over the internet.

And this is done. What strikes me as peculiar is when VPN is used with public/routable addresses. The address is still discoverable, because it is public and no amount of secrecy will change that. The house is on a public street – no matter that the occupant is not listed in the phone book and has his mail sent to the post office. It will be a part of a range that has some other member of it in a public DNS. Therefore it is discoverable through scanning. This is also why services should not run on default ports. And all services running on default port should be disabled as far as possible. Knowing an IP is only half the battle, you still need the right port if you are going to attack something.

Add VPN to the public address and unknown traffic will be prevented from reaching it. Which negates any need to keep it secret – not that you could even if you wanted too. Which leaves no role for secrecy when it comes to IP addresses.

Why even use a public address if you are going to use VPN? They are neither free nor plentiful. Well, you shouldn’t. But if you do, it must be for reasons of convenience. They are unique after all. There is no need to agree a private/non-routable address with the counterparty so as not to cause a conflict with something else in their network. Adding NAT-ing here is just silly as it simply adds confusion and does nothing for security. With one exception: if there is a failure to agree on a single mutually acceptable private address among multiple parties. If there is a hold out, there might have to be NAT-ing between that party and the others.

No, a VPN tunnel should be from one private, non-routable address to another. Not that this needs to be point-to-point. You can route all kinds of traffic though a single VPN tunnel. Your routing tables control that.

Server A has address 10.1.0.10 and sends traffic to Server B at 10.2.0.10 over a VPN. And vice versa. They belong to two separate organization and separate private networks.

The VPN tunnel has openings 10.1.0.1 and 10.2.0.1 respectively. Server A routes traffic bound for 10.2.0.10, to 10.1.0.1. Server B routes traffic bound for 10.1.0.10, to 10.2.0.1.

All of these addresses could be freely published and it would do any external attacker no good at all. Security without secrecy.

federated rigamarole (dual Norwegian and English)

Hvor mange nettsteder er man innom dersom man logger seg inn på NAV med BankId. Er det fler enn 10 ?
Det rette antallet er faktisk 14, spred over 7 domener. I disse GDPR tider kan det være instruktivt å se hvem som følger med på deg når du logger inn på NAV.

Gå til https :// www . nav . no/ og slå på Web Console før du starter med inloggingen , så får du se. Jeg gjorde dette, lagret resultatet til en HAR-fil og gjorde noen enkle uttrekk fra denne.

egrep “\”url\”:” HAR-file | sed ‘s/.*”url”: “htt[^\/]*\/\///’ | sed ‘s/\/.*//’ | sed ‘s/.*\.\([^\.]*\.[^\.]*\)$/\1/’ | sort | uniq -c | sort -r

61 nav.no
55 difi.no
14 bankid.no
5 psplugin.com
2 taskanalytics.com
2 microsoftonline.com
2 googletagmanager.com

We’re definitely at nav.no, with a total of 61 calls there. Bankid.no is as expected; And difi.no is no surprice as the government federation gateway (55 calls).
Men så blir det interessant. De 3 nederste på listen er noe overaskende. Når det det nødvendig å koble in Microsoft for en pålogging til NAV ?
Det er heller ikke åpenbart at Google trenger å vite når noen innom NAV. Selv om det nok er kunder av Google Analytics som gjerne kunne tenke seg å vite det.

But who are making these quiestioanable calls ?
Going back to the HAR-file.

egrep -v “text\”:” HAR-file | tr -d “\n” | sed ‘s/”url”:/\n “url\”:/g’ | sed ‘s/ */ /g’ | egrep “Referer” | sed ‘s/”url”: “\([^\”]*\)”.*{ “name”: “Referer”, “value”: “\([^\”]*\).*/\2 \1 /g’ | sed ‘s/ [^/]*:\/\/\([^/]*\)\/[^ ]* [^/]*:\/\/\([^/]*\)\/[^ ]*/\1 \2/’ | sort | uniq

appres.nav.no appres.nav.no
csfe.bankid.no csfe.bankid.no
csfe.bankid.no idporten.difi.no
idporten.difi.no csfe.bankid.no
idporten.difi.no idporten.difi.no
idporten.difi.no oidc.difi.no
oidc.difi.no login.microsoftonline.com
oidc.difi.no loginservice.nav.no
oidc.difi.no http://www.nav.no
http://www.nav.no account.psplugin.com
http://www.nav.no appres.nav.no
http://www.nav.no eumgw.nav.no
http://www.nav.no idporten.difi.no
http://www.nav.no in.taskanalytics.com
http://www.nav.no jsagent.nav.no
http://www.nav.no login.microsoftonline.com
http://www.nav.no loginservice.nav.no
http://www.nav.no nav.psplugin.com
http://www.nav.no oidc.difi.no
http://www.nav.no tjenester.nav.no
http://www.nav.no http://www.googletagmanager.com
http://www.nav.no http://www.nav.no

The culprit is NAV itself. It is their web application which is making calls to Google.
The calls to psplugin.com, taskanalytics.com and googletagmanager.com are all only from NAV

The microsoft call is made by Difi too. So let’s look at that first.

The following command extracts the domain call and redirect sequence. (HTTP 302 redirects)

egrep -v “text\”:” HAR-file | tr -d “\n” | sed ‘s/”url”:/\n “url\”:/g’ | sed ‘s/ */ /g’ | egrep “\”status\”: 302″ | sed ‘s/\(\”url\”: \”[^\”]*\”\).*\”Location\”, \”value\”: \(\”[^\”]*\).*/\n\n\n\1\n\n\”Location\”: \2/’

Showing the url being called and the URL being redirected too (the Location HTTP header sent back to the browser from the site along with the HTTP 302 code) when calling that URL.

“url”: “https://tjenester.nav.no/dittnav/oversikt”
“Location”: “https://www.nav.no/person/dittnav/

“url”: “https://loginservice.nav.no/login?level=Level3&redirect=https://www.nav.no/person/dittnav/”
“Location”: “https://login.microsoftonline.com/navnob2c.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1a_idporten&response_type=code&client_id=45104d6a-f5bc-4e8c-b352-4bbfc9381f25&redirect_uri=https%3A%2F%2Floginservice.nav.no%2Fcallback&scope=openid+offline_access+45104d6a-f5bc-4e8c-b352-4bbfc9381f25&state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&nonce=HLPaFgxW368_-E6Rj5L6D0iT4yufUO6kydE21oT3QJE&level=Level3

“url”: “https://login.microsoftonline.com/navnob2c.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1a_idporten&response_type=code&client_id=45104d6a-f5bc-4e8c-b352-4bbfc9381f25&redirect_uri=https%3A%2F%2Floginservice.nav.no%2Fcallback&scope=openid+offline_access+45104d6a-f5bc-4e8c-b352-4bbfc9381f25&state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&nonce=HLPaFgxW368_-E6Rj5L6D0iT4yufUO6kydE21oT3QJE&level=Level3”

“Location”: “https://oidc.difi.no/idporten-oidc-provider/authorize?client_id=oidc_nav&redirect_uri=https%3a%2f%2flogin.microsoftonline.com%2fte%2fnavnob2c.onmicrosoft.com%2foauth2%2fauthresp&response_type=code&scope=openid&response_mode=form_post&nonce=%2fC9sCl2kb7TZMD4tPS1%2fAg%3d%3d&acr_values=Level3&state=StateProperties%3deyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0

“url”: “https://oidc.difi.no/idporten-oidc-provider/authorize?client_id=oidc_nav&redirect_uri=https%3a%2f%2flogin.microsoftonline.com%2fte%2fnavnob2c.onmicrosoft.com%2foauth2%2fauthresp&response_type=code&scope=openid&response_mode=form_post&nonce=%2fC9sCl2kb7TZMD4tPS1%2fAg%3d%3d&acr_values=Level3&state=StateProperties%3deyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0”

“Location”: “https://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?SAMLRequest=nZRNj5swEIbv%2FRXId8JHaBosYJVNumqkbUMD20MvK689bCyBTW2TTf99DQkpldocekKaGT%2Fzet4xyd2pqZ0jKM2lSFEw85EDgkrGxWuKnsoHd4nusneJJk0dtnjVmYPYw48OtHFWWoMy9txaCt01oApQR07haf%2BYooMxrcaeJzmjM8YrPhMSR9Hc46yVyoBw%2B4zbKnnkDJRHRhi9wJCzsU24IGZQNvLG4yPTky0IraVXFLs9MK6AGq8BQ1Y1J9oTUr1CX2bPRch5kIrCcIkUVaTWgJztJkXP7xdx6H%2BI%2FaW%2FWIY08oN5RBc%2B8%2BNg%2FrJYLGNbpnUHW6ENESZFoR%2FEbhC4flwGMfYjHMSzOF5%2BR06upJFU1vdcnGfYKYEl0VxjQRrQ2FBcrD4%2F4nDm45dzkcafyjJ3811RIufb6EXYe2HdERqfp3%2Bb1V4ao%2BxsFh4UqynhNuDqAMqmpiXeFJclDcMfT9aAXqS%2B0Bt2G937wYghVttO3MOB1NWuGro8C3JMvEkw8f5okI2b98VCt5tc1pz%2BdFZ1Ld%2FWCoiBFBnVweBsQ8xtGX2EM7caSnHbD1rbRgY5Rd7zv3aktpcGlaLpBJB3VXFZfWDDDtm9N3Ayzlo2LVFc9641XPCma64uTAvXtZ3xHqr%2F8uRmGcW0Z9twbj9vUrF%2BD%2B1TAFYqInT%2FZkYj%2F6YouyT%2FccPf6ekPIPsF&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=Avn4sIA3WxkCiEEZZwGkiJ4csP3FzR14fCBEEeKwbTLfqsWz8tRyoVJiNY7POtD%2BvVvjCk4MtJMCqBDxWyycVSzzDj%2F9i507Qef36D5V2Ai265ekyAPECvg5rR%2BgVB3ZkpDbWEBbTNR2wMAzH%2FKiND623p%2BMfBOa5vyUE7HEArJKumjAI4HdZHOfuLtFDGksdI5dGkZAiXs2h5ab5k4TvO8h0tqe%2BFjb333S4ZGb2vL%2B4TSuziNhjDJVISxjQcuCxCxF6Rj%2BN2qWO0ERHxge2v1rJO8awdZAkFU%2FrKz5MHxGJ27paaIZXg4pArkPAMdvs%2FaHetR%2Ff4LeFaMJM6UQUg%3D%3D&locale=nb

“url”: “https://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?SAMLRequest=nZRNj5swEIbv%2FRXId8JHaBosYJVNumqkbUMD20MvK689bCyBTW2TTf99DQkpldocekKaGT%2Fzet4xyd2pqZ0jKM2lSFEw85EDgkrGxWuKnsoHd4nusneJJk0dtnjVmYPYw48OtHFWWoMy9txaCt01oApQR07haf%2BYooMxrcaeJzmjM8YrPhMSR9Hc46yVyoBw%2B4zbKnnkDJRHRhi9wJCzsU24IGZQNvLG4yPTky0IraVXFLs9MK6AGq8BQ1Y1J9oTUr1CX2bPRch5kIrCcIkUVaTWgJztJkXP7xdx6H%2BI%2FaW%2FWIY08oN5RBc%2B8%2BNg%2FrJYLGNbpnUHW6ENESZFoR%2FEbhC4flwGMfYjHMSzOF5%2BR06upJFU1vdcnGfYKYEl0VxjQRrQ2FBcrD4%2F4nDm45dzkcafyjJ3811RIufb6EXYe2HdERqfp3%2Bb1V4ao%2BxsFh4UqynhNuDqAMqmpiXeFJclDcMfT9aAXqS%2B0Bt2G937wYghVttO3MOB1NWuGro8C3JMvEkw8f5okI2b98VCt5tc1pz%2BdFZ1Ld%2FWCoiBFBnVweBsQ8xtGX2EM7caSnHbD1rbRgY5Rd7zv3aktpcGlaLpBJB3VXFZfWDDDtm9N3Ayzlo2LVFc9641XPCma64uTAvXtZ3xHqr%2F8uRmGcW0Z9twbj9vUrF%2BD%2B1TAFYqInT%2FZkYj%2F6YouyT%2FccPf6ekPIPsF&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=Avn4sIA3WxkCiEEZZwGkiJ4csP3FzR14fCBEEeKwbTLfqsWz8tRyoVJiNY7POtD%2BvVvjCk4MtJMCqBDxWyycVSzzDj%2F9i507Qef36D5V2Ai265ekyAPECvg5rR%2BgVB3ZkpDbWEBbTNR2wMAzH%2FKiND623p%2BMfBOa5vyUE7HEArJKumjAI4HdZHOfuLtFDGksdI5dGkZAiXs2h5ab5k4TvO8h0tqe%2BFjb333S4ZGb2vL%2B4TSuziNhjDJVISxjQcuCxCxF6Rj%2BN2qWO0ERHxge2v1rJO8awdZAkFU%2FrKz5MHxGJ27paaIZXg4pArkPAMdvs%2FaHetR%2Ff4LeFaMJM6UQUg%3D%3D&locale=nb”

“Location”: “https://idporten.difi.no:443/opensso/UI/Login?realm=/norge.no&spEntityID=oidc.difi.no&service=IDPortenLevel3List&goto=http://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID%3D_5692079080682c40134c60d0913b6689%26index%3Dnull%26acsURL%3Dhttps://oidc.difi.no:443/idporten-oidc-provider/assertionconsumer%26spEntityID%3Doidc.difi.no%26binding%3Durn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST

 

“url”: “https://idporten.difi.no/opensso/bidresponse”

“Location”: “https://idporten.difi.no:443/opensso/UI/Login?realm=norge.no&ForceAuth=&gx_charset=UTF-8&locale=nb&goto=http://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID=_5692079080682c40134c60d0913b6689&service=BankIDResponse

 

“url”: “https://idporten.difi.no/opensso/UI/Login?realm=norge.no&ForceAuth=&gx_charset=UTF-8&locale=nb&goto=http://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID=_5692079080682c40134c60d0913b6689&service=BankIDResponse”

“Location”: “https://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID=_5692079080682c40134c60d0913b6689

“url”: “https://oidc.difi.no/idporten-oidc-provider/assertionconsumer”

“Location”: “https://oidc.difi.no/idporten-oidc-provider/consent?mid=_5692079080682c40134c60d0913b6689

 

“url”: “https://login.microsoftonline.com/te/navnob2c.onmicrosoft.com/oauth2/authresp”

“Location”: “https://loginservice.nav.no/callback?state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&code=eyJraWQiOiJhT05QQk9fWDV0bzNIX2tsMllSTjRFRGdUMkVvQ201bmNCNlB1MEhOSlNJIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6IjEuMCJ9.b5lGSnVxsolX3Wa1gqGh5qqhm8upQh3laxBhYbqC2FixHYog53-6ilhTGxNevcqYL-gFih4xwTqNYJuEH7ux-eRr8YoUcv7Mv1TO3U-VtddA1O7ZMF6mbu3L8DcOFqHR7OahL4j_QVZm9z-gAYFl_yZvAMmQ4Selk_uKAzvwLkjE57u4S61nArLSknOJDV8XwpO4Ow_iicpL5RC_dr4jaLGH6WH6bMgLrtQ2uNfb2KhYQYQhkTmkYjqgx7fgPbqddz0OOCF8PUIEL7sKpl1-d0Uv75iAqXUJofZlFVDcDfBoO6noxaLVkWmNjWvHWmKHbHImmOTD__XtExAMoMK8wg.LJS-OSzaHhkhVERs.LCBP0FbMPn9OKkej4fmYlN9fj-cgwYPCKSulz96qY06wrmMOFokm5Iies7nsPsS2SD5WJGw-D4vlso-ac-yjHqNI_s-KequNz5XiNjMS_gaJYh19bfivmKJmCxOJjrobA95FzBAkJaOHezJNDWP_tlfB-0wzD8Y5JYCYJGw3CXvhlQDtNH3vAprgkEtA9sHxzoz_ejzZwT2Xrb5z2aI8RUJI1Y2WDHLKo8uXfkROJDAajYtWKIm2LcaFwdtnm90kXGHFB7tIRF76L8sOgc2IuK6l3UBlFpJcsaPeY-bvGK9rMotjSKqZjAiIs_OTkcpL_GPNbpyiicjQWdVFLLf51ivWlHvdADrCxDH20yLWu6GiYZMHUW4YXCDODhmrZx4LmEp35v_1Wpji-1HeKH3X7gPgZXVjhL9bK0ApnyCsUy6Vi-P5KyEy8Ne6UV0UKQZQjl58SoV67UKrabt44Wr9CDvYHCQwBh4WwJ-3pw2lF4-FbwXYE9A3ssdbAI5sM9M8XHAt537KRWTgaXw1xmrEQ3VQ8q6nNBIUhEKdtr43-q8NULpc2Yh8Q8fFPhBaUbtYSEeRKl-vrpiKI2yB4deG8bz6dwtgCiHdQ9R81hPCloAqNgUHzIl0roZkyu1acw.BDHTKPyICH1GZs9SIr-Xqg

 

“url”: “https://loginservice.nav.no/callback?state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&code=eyJraWQiOiJhT05QQk9fWDV0bzNIX2tsMllSTjRFRGdUMkVvQ201bmNCNlB1MEhOSlNJIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6IjEuMCJ9.b5lGSnVxsolX3Wa1gqGh5qqhm8upQh3laxBhYbqC2FixHYog53-6ilhTGxNevcqYL-gFih4xwTqNYJuEH7ux-eRr8YoUcv7Mv1TO3U-VtddA1O7ZMF6mbu3L8DcOFqHR7OahL4j_QVZm9z-gAYFl_yZvAMmQ4Selk_uKAzvwLkjE57u4S61nArLSknOJDV8XwpO4Ow_iicpL5RC_dr4jaLGH6WH6bMgLrtQ2uNfb2KhYQYQhkTmkYjqgx7fgPbqddz0OOCF8PUIEL7sKpl1-d0Uv75iAqXUJofZlFVDcDfBoO6noxaLVkWmNjWvHWmKHbHImmOTD__XtExAMoMK8wg.LJS-OSzaHhkhVERs.LCBP0FbMPn9OKkej4fmYlN9fj-cgwYPCKSulz96qY06wrmMOFokm5Iies7nsPsS2SD5WJGw-D4vlso-ac-yjHqNI_s-KequNz5XiNjMS_gaJYh19bfivmKJmCxOJjrobA95FzBAkJaOHezJNDWP_tlfB-0wzD8Y5JYCYJGw3CXvhlQDtNH3vAprgkEtA9sHxzoz_ejzZwT2Xrb5z2aI8RUJI1Y2WDHLKo8uXfkROJDAajYtWKIm2LcaFwdtnm90kXGHFB7tIRF76L8sOgc2IuK6l3UBlFpJcsaPeY-bvGK9rMotjSKqZjAiIs_OTkcpL_GPNbpyiicjQWdVFLLf51ivWlHvdADrCxDH20yLWu6GiYZMHUW4YXCDODhmrZx4LmEp35v_1Wpji-1HeKH3X7gPgZXVjhL9bK0ApnyCsUy6Vi-P5KyEy8Ne6UV0UKQZQjl58SoV67UKrabt44Wr9CDvYHCQwBh4WwJ-3pw2lF4-FbwXYE9A3ssdbAI5sM9M8XHAt537KRWTgaXw1xmrEQ3VQ8q6nNBIUhEKdtr43-q8NULpc2Yh8Q8fFPhBaUbtYSEeRKl-vrpiKI2yB4deG8bz6dwtgCiHdQ9R81hPCloAqNgUHzIl0roZkyu1acw.BDHTKPyICH1GZs9SIr-Xqg”

“Location”: “https://www.nav.no/person/dittnav/

 

So the sequence is from NAV to Microsoft to Difi and then reversing the steps back again. Which is how Micorsoft is called by both Difi and NAV.

Where are the calls to psplugin.com, taskanalytics.com and googletagmanager.com from, and more particularly what are they?

egrep -v “text\”:” HAR-file | tr -d “\n” | sed ‘s/”url”:/\n “url\”:/g’ | sed ‘s/ */ /g’ | egrep “Referer” | sed ‘s/”url”: “\([^\”]*\)”.*{ “name”: “Referer”, “value”: “\([^\”]*\).*/\2 \1 /g’ | egrep “(psplugin.com|taskanalytics.com|googletagmanager.com)”

https://www.nav.no/person/dittnav/ https://www.googletagmanager.com/gtm.js?id=GTM-PM9RP3
https://www.nav.no/person/dittnav/ https://in.taskanalytics.com/02013/tm.js?r=skip&1573326257975
https://www.nav.no/person/dittnav/ https://www.googletagmanager.com/gtm.js?id=GTM-PM9RP3
https://www.nav.no/person/dittnav/ https://in.taskanalytics.com/02013/tm.js?r=skip&1573326295196
https://www.nav.no/person/dittnav/ https://account.psplugin.com/83BD7664-B38B-4EEE-8D99-200669A32551/ps.js
https://www.nav.no/person/dittnav/ https://nav.psplugin.com/api/v1/session/bucket/visitor?json=true&sessionId=f1f43342-d73f-4242-aaad-cc5a951d83b7%2BFogm7TkHIHjpVxuZ4w0e6KDH9p2WZkmphcX6U9L4%3D
https://www.nav.no/person/dittnav/ https://nav.psplugin.com/api/v1/Group/Status/83bd7664-b38b-4eee-8d99-200669a32551?json=true&sessionId=f1f43342-d73f-4242-aaad-cc5a951d83b7%2BFogm7TkHIHjpVxuZ4w0e6KDH9p2WZkmphcX6U9L4%3D&groupId=D3F9B5D9-C9FD-43AD-BA23-6E112D23ABFC&groupId=0D034F9F-CD29-4E4D-BD26-9C943D8D5557&groupId=641833F0-C54C-4BDE-9DDF-6AFF0A512FF5&groupId=85723614-0E9A-45CF-93C3-445DCDBF87FE&groupId=975CAC35-8D3E-402C-B9E3-0930D30FFFB7&groupId=D48EC512-991E-4541-8062-CAF97C3757D9&groupId=A034081B-6B73-46B7-BE27-23B8E9CE3079
https://www.nav.no/person/dittnav/ https://nav.psplugin.com/api/v1/batch/?json=true&sessionId=f1f43342-d73f-4242-aaad-cc5a951d83b7%2BFogm7TkHIHjpVxuZ4w0e6KDH9p2WZkmphcX6U9L4%3D
https://www.nav.no/person/dittnav/ https://nav.psplugin.com/api/v1/batch/?json=true&sessionId=f1f43342-d73f-4242-aaad-cc5a951d83b7%2BFogm7TkHIHjpVxuZ4w0e6KDH9p2WZkmphcX6U9L4%3D

Some things here are not necessarily ok.
psplugin.com has “nav” as a subdomain and the calls go here. Apparently with session specific information. Which is user specific information. Where is it going ?

This command will get the registration info on the domain

curl ‘https://www.site24x7.com/tools/action.do’ -H ‘Content-type: application/x-www-form-urlencoded;charset=UTF-8’ –data “execute=getLocation&isip=false&url=nav.psplugin.com&method=getLocation&timestamp=$(( $(date +%s)-10))” | sed ‘s/#:#/\n/g’

Falkenberg in Sweden. Well, that might be ok geographically. But it is not inside Norway, and NAV is a goverment agency.

Google is in California, but their datacenters are all over.
in.taskanalytics.com gives a Dublin address, again that can mean anything.
Though in either case the location to which data is being sent is not likely in Norway.

Let’s look at some of that data. Are there any POST calls? HTTP POSTs have the highest potential for carrying off data (tough cookies can carry plenty too )

cat HAR-file | tr -d “\n” | sed ‘s/”url”:/\n “url\”:/g’ | sed ‘s/ */ /g’ | egrep -i “\”method\”: \”POST\”” | egrep -v “^ \”url\”: \”https://%5B^/]*.(bankid|nav|difi).no”

“url”: “https://nav.psplugin.com/api/v1/batch/?json=true&sessionId=f1f43342-d73f-4242-aaad-cc5a951d83b7%2BFogm7TkHIHjpVxuZ4w0e6KDH9p2WZkmphcX6U9L4%3D”, “httpVersion”: “HTTP/1.1”, “headers”: [ { “name”: “Host”, “value”: “nav.psplugin.com” }, { “name”: “User-Agent”, “value”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0” }, { “name”: “Accept”, “value”: “application/json” }, { “name”: “Accept-Language”, “value”: “en-GB,en;q=0.5” }, { “name”: “Accept-Encoding”, “value”: “gzip, deflate, br” }, { “name”: “Content-Type”, “value”: “text/plain; charset=utf-8” }, { “name”: “Content-Length”, “value”: “724” }, { “name”: “Origin”, “value”: “https://www.nav.no” }, { “name”: “DNT”, “value”: “1” }, { “name”: “Connection”, “value”: “keep-alive” }, { “name”: “Referer”, “value”: “https://www.nav.no/person/dittnav/” }, { “name”: “Cookie”, “value”: “vngage.srvid=da46b3656037eb53” } ], “cookies”: [ { “name”: “vngage.srvid”, “value”: “da46b3656037eb53” } ], “queryString”: [ { “name”: “json”, “value”: “true” }, { “name”: “sessionId”, “value”: “f1f43342-d73f-4242-aaad-cc5a951d83b7 Fogm7TkHIHjpVxuZ4w0e6KDH9p2WZkmphcX6U9L4=” } ], “headersSize”: 552, “postData”: { “mimeType”: “text/plain; charset=utf-8”, “params”: [], “text”: “{\”items\”:[{\”contentHeaders\”:{\”Content-Type\”:\”application/json\”},\”method\”:\”post\”,\”uri\”:\”https://nav.psplugin.com/api/v1/Tracking/Bundle\”,\”body\”:\”[{\\\”type\\\”:\\\”Navigation\\\”,\\\”url\\\”:\\\”https://www.nav.no/person/dittnav/\\\”,\\\”referrer\\\”:\\\”\\\”,\\\”visitId\\\”:\\\”00000000-0000-0000-0000-000000000000\\\”,\\\”siteId\\\”:\\\”1F1046B2-16A5-40A1-AD72-65B34BA29159\\\”,\\\”metaData\\\”:[{\\\”property\\\”:\\\”triggerType\\\”,\\\”content\\\”:\\\”pageload\\\”}]},{\\\”type\\\”:\\\”Opportunity\\\”,\\\”visitId\\\”:\\\”00000000-0000-0000-0000-000000000000\\\”,\\\”siteId\\\”:\\\”1F1046B2-16A5-40A1-AD72-65B34BA29159\\\”,\\\”opportunityId\\\”:\\\”615FF5E7-37B7-4697-A35F-72598B0DC53B\\\”,\\\”correlationId\\\”:\\\”0B9BA0C0-3C13-4947-A8C3-AFCDDFEEC82B\\\”,\\\”tags\\\”:[],\\\”source\\\”:\\\”visitor\\\”,\\\”tag\\\”:{},\\\”score\\\”:0}]\”}]}” } }, “response”: { “status”: 200, “statusText”: “OK”, “httpVersion”: “HTTP/1.1”, “headers”: [ { “name”: “Date”, “value”: “Sat, 09 Nov 2019 19:04:56 GMT” }, { “name”: “Content-Type”, “value”: “application/json; charset=utf-8” }, { “name”: “Transfer-Encoding”, “value”: “chunked” }, { “name”: “Access-Control-Allow-Credentials”, “value”: “true” }, { “name”: “Access-Control-Allow-Origin”, “value”: “https://www.nav.no” }, { “name”: “Access-Control-Max-Age”, “value”: “604800” }, { “name”: “P3p”, “value”: “CP=\”IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\”” }, { “name”: “X-Content-Type-Options”, “value”: “nosniff” } ], “cookies”: [], “content”: { “mimeType”: “application/json; charset=utf-8”, “size”: 63, “text”: “{\”items\”:[{\”statusCode\”:200,\”headers\”:{},\”contentHeaders\”:{}}]}” }, “redirectURL”: “”, “headersSize”: 361, “bodySize”: 424 }, “cache”: {}, “timings”: { “blocked”: 1, “dns”: 0, “connect”: 0, “ssl”: 0, “send”: 0, “wait”: 47, “receive”: 0 }, “time”: 48, “_securityState”: “secure”, “serverIPAddress”: “194.54.166.38”, “connection”: “443” }, { “pageref”: “page_3”, “startedDateTime”: “2019-11-09T20:04:57.371+01:00”, “request”: { “bodySize”: 5417, “method”: “POST”,

That wasn’t much. Some session ids but not much else.

From where is the call to google in being made and why ?

A javastip file  https://appres.nav.no/_public/beta.nav.no/built-navno/js/navno/google-tag-manager.js

 

This login was very messy and the calls out to external parties most worrysome. But what strikes me as the most unusual is the call to Microsoft. And as a step in the login process too.
Why should Microsoft be involved in a federated login to a government agency ?

 

egrep -v “text\”:” HAR-file | tr -d “\n” | sed ‘s/”url”:/\n “url\”:/g’ | sed ‘s/ */ /g’ | egrep “^ \”url\”: \”https://%5B^/]*.microsoftonline.com” | sed ‘s/”response”/\n\n\n”response”/g’ | sed ‘s/ “url”/\n\n\n”url”/g’

“url”: “https://login.microsoftonline.com/navnob2c.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1a_idporten&response_type=code&client_id=45104d6a-f5bc-4e8c-b352-4bbfc9381f25&redirect_uri=https%3A%2F%2Floginservice.nav.no%2Fcallback&scope=openid+offline_access+45104d6a-f5bc-4e8c-b352-4bbfc9381f25&state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&nonce=HLPaFgxW368_-E6Rj5L6D0iT4yufUO6kydE21oT3QJE&level=Level3”, “httpVersion”: “HTTP/1.1”, “headers”: [ { “name”: “Host”, “value”: “login.microsoftonline.com” }, { “name”: “User-Agent”, “value”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0” }, { “name”: “Accept”, “value”: “text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8” }, { “name”: “Accept-Language”, “value”: “en-GB,en;q=0.5” }, { “name”: “Accept-Encoding”, “value”: “gzip, deflate, br” }, { “name”: “Referer”, “value”: “https://www.nav.no/person/dittnav/” }, { “name”: “DNT”, “value”: “1” }, { “name”: “Connection”, “value”: “keep-alive” }, { “name”: “Upgrade-Insecure-Requests”, “value”: “1” } ], “cookies”: [], “queryString”: [ { “name”: “p”, “value”: “b2c_1a_idporten” }, { “name”: “response_type”, “value”: “code” }, { “name”: “client_id”, “value”: “45104d6a-f5bc-4e8c-b352-4bbfc9381f25” }, { “name”: “redirect_uri”, “value”: “https://loginservice.nav.no/callback” }, { “name”: “scope”, “value”: “openid offline_access 45104d6a-f5bc-4e8c-b352-4bbfc9381f25” }, { “name”: “state”, “value”: “_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk” }, { “name”: “nonce”, “value”: “HLPaFgxW368_-E6Rj5L6D0iT4yufUO6kydE21oT3QJE” }, { “name”: “level”, “value”: “Level3” } ], “headersSize”: 758 },

“response”: { “status”: 302, “statusText”: “Found”, “httpVersion”: “HTTP/1.1”, “headers”: [ { “name”: “Cache-Control”, “value”: “private” }, { “name”: “Content-Type”, “value”: “text/html; charset=utf-8” }, { “name”: “Location”, “value”: “https://oidc.difi.no/idporten-oidc-provider/authorize?client_id=oidc_nav&redirect_uri=https%3a%2f%2flogin.microsoftonline.com%2fte%2fnavnob2c.onmicrosoft.com%2foauth2%2fauthresp&response_type=code&scope=openid&response_mode=form_post&nonce=%2fC9sCl2kb7TZMD4tPS1%2fAg%3d%3d&acr_values=Level3&state=StateProperties%3deyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0” }, { “name”: “x-ms-gateway-requestid”, “value”: “6be20d8a-8de5-4744-9554-0e5d916b0646” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e=aGxSZjI4UFlYMlhxZjN3dGs3bnpZc2Q3dCtSSmtkRDlJNVp6TWxwS3VSQ1VLZmE4UEVjdHBWSStmTWhaVWdHWHQvTU9BRHlBMXhrU2tmanpBaGNNWXc9PTsyMDE5LTExLTA5VDE5OjA0OjE5Ljc1MDE5MTRaO3ZOdVdHUGlMYTZLcVRrN2RJVWZFMmc9PTt7IlRhcmdldEVudGl0eSI6IklkUG9ydGVuRXhjaGFuZ2UiLCJPcmNoZXN0cmF0aW9uU3RlcCI6MX0=; domain=login.microsoftonline.com; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-cache:x-1o-knobkop-5eb8ck9bw_0=m1.zcF9N87I+2/g1yeG.UTmH1gNjIyc69CLP0dMrJg==.0.xoG2yeldPtYiejoQ1QkTa6xU6Mp8IwRk4wbClfYYeaH7BczY8d++EydY4qYxTQSMLySLgHc+nROLyX1zwt4Zfb5gEN4TbAGP9uRMlrKDQE/SN6j5lU1UQA7nYqAIG+yq0t4BsO0KCh7Y9cK2oLi8S12xFGXwFHaB76r6DH4ZTaaJAROmz0cD/NAohTjqqi8YgrK0Lz03x64r0dbjHXTyXhgJJy91KBPGeTXc98WseRgsw429BSVfJToIC7rEfHk8ugnPZfZVIY7k13n1DGzpzKjfFZ67LsS6KEUg3YBDcs0AQULdPWZ15Bn0hk9vwfkBWMUi3kZRPxyfQyktCktF3wcbYQ5VYZh4f6BMz2RLqQHMPIDwzB5GSZvRuW7YkAywNb6dFS8yN4c9mx7EfgQjuexVmeJv+asyUASINQANZmpgHQQbDN/skHbOpSr4Zf+Sr/7wC0hy8vueOQFJad6hu6WYKp10b2MFlmLnnZyr9jeVdQEvTp0fsRu/6xacCH5fHG9VvjooZax89P8sBEyA/1HMGRURxGtaJpKHCllTlGaYrQYgn4ILcnANDHW8DWawHKM6sB8a2nS056/yyiPGVMaG+YV08qdWd/xM6J5I2e4KXzxKYdEIFYPVVg8otyp6M/mKK+QIxvHKKdcnGE93JcdYKhC0pOjznhQuxaaEZvXn8bit+WWzPeYxeSPWDQadXUNSXwG4L66AWn/X; domain=login.microsoftonline.com; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-trans=eyJUX0RJQyI6W3siSSI6ImZhNjhlZGM3LWU4NDktNDMwNi04ZmZiLTkxMWJmMDI5M2Q2ZiIsIlQiOiJuYXZub2IyYy5vbm1pY3Jvc29mdC5jb20iLCJQIjoiYjJjXzFhX2lkcG9ydGVuIiwiQyI6IjQ1MTA0ZDZhLWY1YmMtNGU4Yy1iMzUyLTRiYmZjOTM4MWYyNSIsIlMiOjEsIk0iOnt9LCJEIjowfV0sIkNfSUQiOiJmYTY4ZWRjNy1lODQ5LTQzMDYtOGZmYi05MTFiZjAyOTNkNmYifQ==; domain=login.microsoftonline.com; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “X-Frame-Options”, “value”: “DENY” }, { “name”: “Strict-Transport-Security”, “value”: “max-age=31536000; includeSubDomains” }, { “name”: “X-Content-Type-Options”, “value”: “nosniff” }, { “name”: “X-XSS-Protection”, “value”: “1; mode=block” }, { “name”: “Set-Cookie”, “value”: “x-ms-gateway-slice=001-000; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “stsservicecookie=cpim_te; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Date”, “value”: “Sat, 09 Nov 2019 19:04:19 GMT” }, { “name”: “Content-Length”, “value”: “599” } ], “cookies”: [ { “name”: “x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e”, “value”: “aGxSZjI4UFlYMlhxZjN3dGs3bnpZc2Q3dCtSSmtkRDlJNVp6TWxwS3VSQ1VLZmE4UEVjdHBWSStmTWhaVWdHWHQvTU9BRHlBMXhrU2tmanpBaGNNWXc9PTsyMDE5LTExLTA5VDE5OjA0OjE5Ljc1MDE5MTRaO3ZOdVdHUGlMYTZLcVRrN2RJVWZFMmc9PTt7IlRhcmdldEVudGl0eSI6IklkUG9ydGVuRXhjaGFuZ2UiLCJPcmNoZXN0cmF0aW9uU3RlcCI6MX0=” }, { “name”: “x-ms-cpim-cache:x-1o-knobkop-5eb8ck9bw_0”, “value”: “m1.zcF9N87I+2/g1yeG.UTmH1gNjIyc69CLP0dMrJg==.0.xoG2yeldPtYiejoQ1QkTa6xU6Mp8IwRk4wbClfYYeaH7BczY8d++EydY4qYxTQSMLySLgHc+nROLyX1zwt4Zfb5gEN4TbAGP9uRMlrKDQE/SN6j5lU1UQA7nYqAIG+yq0t4BsO0KCh7Y9cK2oLi8S12xFGXwFHaB76r6DH4ZTaaJAROmz0cD/NAohTjqqi8YgrK0Lz03x64r0dbjHXTyXhgJJy91KBPGeTXc98WseRgsw429BSVfJToIC7rEfHk8ugnPZfZVIY7k13n1DGzpzKjfFZ67LsS6KEUg3YBDcs0AQULdPWZ15Bn0hk9vwfkBWMUi3kZRPxyfQyktCktF3wcbYQ5VYZh4f6BMz2RLqQHMPIDwzB5GSZvRuW7YkAywNb6dFS8yN4c9mx7EfgQjuexVmeJv+asyUASINQANZmpgHQQbDN/skHbOpSr4Zf+Sr/7wC0hy8vueOQFJad6hu6WYKp10b2MFlmLnnZyr9jeVdQEvTp0fsRu/6xacCH5fHG9VvjooZax89P8sBEyA/1HMGRURxGtaJpKHCllTlGaYrQYgn4ILcnANDHW8DWawHKM6sB8a2nS056/yyiPGVMaG+YV08qdWd/xM6J5I2e4KXzxKYdEIFYPVVg8otyp6M/mKK+QIxvHKKdcnGE93JcdYKhC0pOjznhQuxaaEZvXn8bit+WWzPeYxeSPWDQadXUNSXwG4L66AWn/X” }, { “name”: “x-ms-cpim-trans”, “value”: “eyJUX0RJQyI6W3siSSI6ImZhNjhlZGM3LWU4NDktNDMwNi04ZmZiLTkxMWJmMDI5M2Q2ZiIsIlQiOiJuYXZub2IyYy5vbm1pY3Jvc29mdC5jb20iLCJQIjoiYjJjXzFhX2lkcG9ydGVuIiwiQyI6IjQ1MTA0ZDZhLWY1YmMtNGU4Yy1iMzUyLTRiYmZjOTM4MWYyNSIsIlMiOjEsIk0iOnt9LCJEIjowfV0sIkNfSUQiOiJmYTY4ZWRjNy1lODQ5LTQzMDYtOGZmYi05MTFiZjAyOTNkNmYifQ==” }, { “name”: “x-ms-gateway-slice”, “value”: “001-000” }, { “name”: “stsservicecookie”, “value”: “cpim_te” } ], “content”: { “mimeType”: “text/html; charset=UTF-8”, “size”: 14892, “comment”: “Response bodies are not included.” }, “redirectURL”: “https://oidc.difi.no/idporten-oidc-provider/authorize?client_id=oidc_nav&redirect_uri=https%3a%2f%2flogin.microsoftonline.com%2fte%2fnavnob2c.onmicrosoft.com%2foauth2%2fauthresp&response_type=code&scope=openid&response_mode=form_post&nonce=%2fC9sCl2kb7TZMD4tPS1%2fAg%3d%3d&acr_values=Level3&state=StateProperties%3deyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0”, “headersSize”: 2634, “bodySize”: 17526 }, “cache”: {}, “timings”: { “blocked”: 202, “dns”: 0, “connect”: 79, “ssl”: 120, “send”: 0, “wait”: 110, “receive”: 0 }, “time”: 511, “_securityState”: “secure”, “serverIPAddress”: “40.126.1.165”, “connection”: “443” }, { “pageref”: “page_3”, “startedDateTime”: “2019-11-09T20:04:19.838+01:00”, “request”: { “bodySize”: 0, “method”: “GET”,

 

“url”: “https://login.microsoftonline.com/te/navnob2c.onmicrosoft.com/oauth2/authresp”, “httpVersion”: “HTTP/1.1”, “headers”: [ { “name”: “Host”, “value”: “login.microsoftonline.com” }, { “name”: “User-Agent”, “value”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0” }, { “name”: “Accept”, “value”: “text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8” }, { “name”: “Accept-Language”, “value”: “en-GB,en;q=0.5” }, { “name”: “Accept-Encoding”, “value”: “gzip, deflate, br” }, { “name”: “Content-Type”, “value”: “application/x-www-form-urlencoded” }, { “name”: “Content-Length”, “value”: “212” }, { “name”: “Origin”, “value”: “https://oidc.difi.no” }, { “name”: “DNT”, “value”: “1” }, { “name”: “Connection”, “value”: “keep-alive” }, { “name”: “Referer”, “value”: “https://oidc.difi.no/idporten-oidc-provider/consent?mid=_5692079080682c40134c60d0913b6689” }, { “name”: “Cookie”, “value”: “x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e=aGxSZjI4UFlYMlhxZjN3dGs3bnpZc2Q3dCtSSmtkRDlJNVp6TWxwS3VSQ1VLZmE4UEVjdHBWSStmTWhaVWdHWHQvTU9BRHlBMXhrU2tmanpBaGNNWXc9PTsyMDE5LTExLTA5VDE5OjA0OjE5Ljc1MDE5MTRaO3ZOdVdHUGlMYTZLcVRrN2RJVWZFMmc9PTt7IlRhcmdldEVudGl0eSI6IklkUG9ydGVuRXhjaGFuZ2UiLCJPcmNoZXN0cmF0aW9uU3RlcCI6MX0=; x-ms-cpim-cache:x-1o-knobkop-5eb8ck9bw_0=m1.zcF9N87I+2/g1yeG.UTmH1gNjIyc69CLP0dMrJg==.0.xoG2yeldPtYiejoQ1QkTa6xU6Mp8IwRk4wbClfYYeaH7BczY8d++EydY4qYxTQSMLySLgHc+nROLyX1zwt4Zfb5gEN4TbAGP9uRMlrKDQE/SN6j5lU1UQA7nYqAIG+yq0t4BsO0KCh7Y9cK2oLi8S12xFGXwFHaB76r6DH4ZTaaJAROmz0cD/NAohTjqqi8YgrK0Lz03x64r0dbjHXTyXhgJJy91KBPGeTXc98WseRgsw429BSVfJToIC7rEfHk8ugnPZfZVIY7k13n1DGzpzKjfFZ67LsS6KEUg3YBDcs0AQULdPWZ15Bn0hk9vwfkBWMUi3kZRPxyfQyktCktF3wcbYQ5VYZh4f6BMz2RLqQHMPIDwzB5GSZvRuW7YkAywNb6dFS8yN4c9mx7EfgQjuexVmeJv+asyUASINQANZmpgHQQbDN/skHbOpSr4Zf+Sr/7wC0hy8vueOQFJad6hu6WYKp10b2MFlmLnnZyr9jeVdQEvTp0fsRu/6xacCH5fHG9VvjooZax89P8sBEyA/1HMGRURxGtaJpKHCllTlGaYrQYgn4ILcnANDHW8DWawHKM6sB8a2nS056/yyiPGVMaG+YV08qdWd/xM6J5I2e4KXzxKYdEIFYPVVg8otyp6M/mKK+QIxvHKKdcnGE93JcdYKhC0pOjznhQuxaaEZvXn8bit+WWzPeYxeSPWDQadXUNSXwG4L66AWn/X; x-ms-cpim-trans=eyJUX0RJQyI6W3siSSI6ImZhNjhlZGM3LWU4NDktNDMwNi04ZmZiLTkxMWJmMDI5M2Q2ZiIsIlQiOiJuYXZub2IyYy5vbm1pY3Jvc29mdC5jb20iLCJQIjoiYjJjXzFhX2lkcG9ydGVuIiwiQyI6IjQ1MTA0ZDZhLWY1YmMtNGU4Yy1iMzUyLTRiYmZjOTM4MWYyNSIsIlMiOjEsIk0iOnt9LCJEIjowfV0sIkNfSUQiOiJmYTY4ZWRjNy1lODQ5LTQzMDYtOGZmYi05MTFiZjAyOTNkNmYifQ==; x-ms-gateway-slice=001-000; stsservicecookie=cpim_te” }, { “name”: “Upgrade-Insecure-Requests”, “value”: “1” } ], “cookies”: [ { “name”: “x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e”, “value”: “aGxSZjI4UFlYMlhxZjN3dGs3bnpZc2Q3dCtSSmtkRDlJNVp6TWxwS3VSQ1VLZmE4UEVjdHBWSStmTWhaVWdHWHQvTU9BRHlBMXhrU2tmanpBaGNNWXc9PTsyMDE5LTExLTA5VDE5OjA0OjE5Ljc1MDE5MTRaO3ZOdVdHUGlMYTZLcVRrN2RJVWZFMmc9PTt7IlRhcmdldEVudGl0eSI6IklkUG9ydGVuRXhjaGFuZ2UiLCJPcmNoZXN0cmF0aW9uU3RlcCI6MX0=” }, { “name”: “x-ms-cpim-cache:x-1o-knobkop-5eb8ck9bw_0”, “value”: “m1.zcF9N87I+2/g1yeG.UTmH1gNjIyc69CLP0dMrJg==.0.xoG2yeldPtYiejoQ1QkTa6xU6Mp8IwRk4wbClfYYeaH7BczY8d++EydY4qYxTQSMLySLgHc+nROLyX1zwt4Zfb5gEN4TbAGP9uRMlrKDQE/SN6j5lU1UQA7nYqAIG+yq0t4BsO0KCh7Y9cK2oLi8S12xFGXwFHaB76r6DH4ZTaaJAROmz0cD/NAohTjqqi8YgrK0Lz03x64r0dbjHXTyXhgJJy91KBPGeTXc98WseRgsw429BSVfJToIC7rEfHk8ugnPZfZVIY7k13n1DGzpzKjfFZ67LsS6KEUg3YBDcs0AQULdPWZ15Bn0hk9vwfkBWMUi3kZRPxyfQyktCktF3wcbYQ5VYZh4f6BMz2RLqQHMPIDwzB5GSZvRuW7YkAywNb6dFS8yN4c9mx7EfgQjuexVmeJv+asyUASINQANZmpgHQQbDN/skHbOpSr4Zf+Sr/7wC0hy8vueOQFJad6hu6WYKp10b2MFlmLnnZyr9jeVdQEvTp0fsRu/6xacCH5fHG9VvjooZax89P8sBEyA/1HMGRURxGtaJpKHCllTlGaYrQYgn4ILcnANDHW8DWawHKM6sB8a2nS056/yyiPGVMaG+YV08qdWd/xM6J5I2e4KXzxKYdEIFYPVVg8otyp6M/mKK+QIxvHKKdcnGE93JcdYKhC0pOjznhQuxaaEZvXn8bit+WWzPeYxeSPWDQadXUNSXwG4L66AWn/X” }, { “name”: “x-ms-cpim-trans”, “value”: “eyJUX0RJQyI6W3siSSI6ImZhNjhlZGM3LWU4NDktNDMwNi04ZmZiLTkxMWJmMDI5M2Q2ZiIsIlQiOiJuYXZub2IyYy5vbm1pY3Jvc29mdC5jb20iLCJQIjoiYjJjXzFhX2lkcG9ydGVuIiwiQyI6IjQ1MTA0ZDZhLWY1YmMtNGU4Yy1iMzUyLTRiYmZjOTM4MWYyNSIsIlMiOjEsIk0iOnt9LCJEIjowfV0sIkNfSUQiOiJmYTY4ZWRjNy1lODQ5LTQzMDYtOGZmYi05MTFiZjAyOTNkNmYifQ==” }, { “name”: “x-ms-gateway-slice”, “value”: “001-000” }, { “name”: “stsservicecookie”, “value”: “cpim_te” } ], “queryString”: [], “headersSize”: 2093, “postData”: { “mimeType”: “application/x-www-form-urlencoded”, “params”: [ { “name”: “code”, “value”: “MryzERHWMbxfjnvLYEiJpw7_ojLZ4qKowtDMHytb7I0” }, { “name”: “state”, “value”: “StateProperties=eyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0” } ], } },

“response”: { “status”: 302, “statusText”: “Found”, “httpVersion”: “HTTP/1.1”, “headers”: [ { “name”: “Cache-Control”, “value”: “private” }, { “name”: “Content-Type”, “value”: “text/html; charset=utf-8” }, { “name”: “Location”, “value”: “https://loginservice.nav.no/callback?state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&code=eyJraWQiOiJhT05QQk9fWDV0bzNIX2tsMllSTjRFRGdUMkVvQ201bmNCNlB1MEhOSlNJIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6IjEuMCJ9.b5lGSnVxsolX3Wa1gqGh5qqhm8upQh3laxBhYbqC2FixHYog53-6ilhTGxNevcqYL-gFih4xwTqNYJuEH7ux-eRr8YoUcv7Mv1TO3U-VtddA1O7ZMF6mbu3L8DcOFqHR7OahL4j_QVZm9z-gAYFl_yZvAMmQ4Selk_uKAzvwLkjE57u4S61nArLSknOJDV8XwpO4Ow_iicpL5RC_dr4jaLGH6WH6bMgLrtQ2uNfb2KhYQYQhkTmkYjqgx7fgPbqddz0OOCF8PUIEL7sKpl1-d0Uv75iAqXUJofZlFVDcDfBoO6noxaLVkWmNjWvHWmKHbHImmOTD__XtExAMoMK8wg.LJS-OSzaHhkhVERs.LCBP0FbMPn9OKkej4fmYlN9fj-cgwYPCKSulz96qY06wrmMOFokm5Iies7nsPsS2SD5WJGw-D4vlso-ac-yjHqNI_s-KequNz5XiNjMS_gaJYh19bfivmKJmCxOJjrobA95FzBAkJaOHezJNDWP_tlfB-0wzD8Y5JYCYJGw3CXvhlQDtNH3vAprgkEtA9sHxzoz_ejzZwT2Xrb5z2aI8RUJI1Y2WDHLKo8uXfkROJDAajYtWKIm2LcaFwdtnm90kXGHFB7tIRF76L8sOgc2IuK6l3UBlFpJcsaPeY-bvGK9rMotjSKqZjAiIs_OTkcpL_GPNbpyiicjQWdVFLLf51ivWlHvdADrCxDH20yLWu6GiYZMHUW4YXCDODhmrZx4LmEp35v_1Wpji-1HeKH3X7gPgZXVjhL9bK0ApnyCsUy6Vi-P5KyEy8Ne6UV0UKQZQjl58SoV67UKrabt44Wr9CDvYHCQwBh4WwJ-3pw2lF4-FbwXYE9A3ssdbAI5sM9M8XHAt537KRWTgaXw1xmrEQ3VQ8q6nNBIUhEKdtr43-q8NULpc2Yh8Q8fFPhBaUbtYSEeRKl-vrpiKI2yB4deG8bz6dwtgCiHdQ9R81hPCloAqNgUHzIl0roZkyu1acw.BDHTKPyICH1GZs9SIr-Xqg” }, { “name”: “x-ms-gateway-requestid”, “value”: “9c4f492d-2cb5-4b76-a4b1-f23caceeebf4” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e=; domain=login.microsoftonline.com; expires=Fri, 08-Nov-2019 19:04:53 GMT; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-sso:navnob2c.onmicrosoft.com_0=m1.RP3BbsClW5XQVM+s.zoR66H3kXPuUX94F/tcPBw==.0.QGnjHX4eTe5vLHtrfAdtBkA0ZJK6aAaPM8CWVJSWvSLqR3JiWGuA0+9m9o2rYn2RUncXsHAlg3bAFD2rBSv69N96/niU3312pxLnuetVzCHHVneCRL0kw8OhYa5NQeHct+Vr4sC11K49f+9e5Cnvi8cVx/qntlWx0JWDqGpQhxFiSGJXBfk0sjr039GL7cvGCWezUbvjbQnz1cF6n8hCWqCk; domain=login.microsoftonline.com; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-cache:x-1o-knobkop-5eb8ck9bw_0=; domain=login.microsoftonline.com; expires=Fri, 08-Nov-2019 19:04:53 GMT; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “x-ms-cpim-trans=; domain=login.microsoftonline.com; expires=Fri, 08-Nov-2019 19:04:53 GMT; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “X-Frame-Options”, “value”: “DENY” }, { “name”: “Strict-Transport-Security”, “value”: “max-age=31536000; includeSubDomains” }, { “name”: “X-Content-Type-Options”, “value”: “nosniff” }, { “name”: “X-XSS-Protection”, “value”: “1; mode=block” }, { “name”: “Set-Cookie”, “value”: “x-ms-gateway-slice=001-000; path=/; SameSite=None; secure; HttpOnly” }, { “name”: “Set-Cookie”, “value”: “stsservicecookie=cpim_te; path=/; secure; HttpOnly” }, { “name”: “Date”, “value”: “Sat, 09 Nov 2019 19:04:53 GMT” }, { “name”: “Content-Length”, “value”: “1359” } ], “cookies”: [ { “name”: “x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e”, “value”: “” }, { “name”: “x-ms-cpim-sso:navnob2c.onmicrosoft.com_0”, “value”: “m1.RP3BbsClW5XQVM+s.zoR66H3kXPuUX94F/tcPBw==.0.QGnjHX4eTe5vLHtrfAdtBkA0ZJK6aAaPM8CWVJSWvSLqR3JiWGuA0+9m9o2rYn2RUncXsHAlg3bAFD2rBSv69N96/niU3312pxLnuetVzCHHVneCRL0kw8OhYa5NQeHct+Vr4sC11K49f+9e5Cnvi8cVx/qntlWx0JWDqGpQhxFiSGJXBfk0sjr039GL7cvGCWezUbvjbQnz1cF6n8hCWqCk” }, { “name”: “x-ms-cpim-cache:x-1o-knobkop-5eb8ck9bw_0”, “value”: “” }, { “name”: “x-ms-cpim-trans”, “value”: “” }, { “name”: “x-ms-gateway-slice”, “value”: “001-000” }, { “name”: “stsservicecookie”, “value”: “cpim_te” } ], “content”: { “mimeType”: “text/html; charset=utf-8”, “size”: 44986, “comment”: “Response bodies are not included.” }, “redirectURL”: “https://loginservice.nav.no/callback?state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&code=eyJraWQiOiJhT05QQk9fWDV0bzNIX2tsMllSTjRFRGdUMkVvQ201bmNCNlB1MEhOSlNJIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6IjEuMCJ9.b5lGSnVxsolX3Wa1gqGh5qqhm8upQh3laxBhYbqC2FixHYog53-6ilhTGxNevcqYL-gFih4xwTqNYJuEH7ux-eRr8YoUcv7Mv1TO3U-VtddA1O7ZMF6mbu3L8DcOFqHR7OahL4j_QVZm9z-gAYFl_yZvAMmQ4Selk_uKAzvwLkjE57u4S61nArLSknOJDV8XwpO4Ow_iicpL5RC_dr4jaLGH6WH6bMgLrtQ2uNfb2KhYQYQhkTmkYjqgx7fgPbqddz0OOCF8PUIEL7sKpl1-d0Uv75iAqXUJofZlFVDcDfBoO6noxaLVkWmNjWvHWmKHbHImmOTD__XtExAMoMK8wg.LJS-OSzaHhkhVERs.LCBP0FbMPn9OKkej4fmYlN9fj-cgwYPCKSulz96qY06wrmMOFokm5Iies7nsPsS2SD5WJGw-D4vlso-ac-yjHqNI_s-KequNz5XiNjMS_gaJYh19bfivmKJmCxOJjrobA95FzBAkJaOHezJNDWP_tlfB-0wzD8Y5JYCYJGw3CXvhlQDtNH3vAprgkEtA9sHxzoz_ejzZwT2Xrb5z2aI8RUJI1Y2WDHLKo8uXfkROJDAajYtWKIm2LcaFwdtnm90kXGHFB7tIRF76L8sOgc2IuK6l3UBlFpJcsaPeY-bvGK9rMotjSKqZjAiIs_OTkcpL_GPNbpyiicjQWdVFLLf51ivWlHvdADrCxDH20yLWu6GiYZMHUW4YXCDODhmrZx4LmEp35v_1Wpji-1HeKH3X7gPgZXVjhL9bK0ApnyCsUy6Vi-P5KyEy8Ne6UV0UKQZQjl58SoV67UKrabt44Wr9CDvYHCQwBh4WwJ-3pw2lF4-FbwXYE9A3ssdbAI5sM9M8XHAt537KRWTgaXw1xmrEQ3VQ8q6nNBIUhEKdtr43-q8NULpc2Yh8Q8fFPhBaUbtYSEeRKl-vrpiKI2yB4deG8bz6dwtgCiHdQ9R81hPCloAqNgUHzIl0roZkyu1acw.BDHTKPyICH1GZs9SIr-Xqg”, “headersSize”: 2574, “bodySize”: 11337 }, “cache”: {}, “timings”: { “blocked”: 0, “dns”: 0, “connect”: 0, “ssl”: 0, “send”: 0, “wait”: 426, “receive”: 0 }, “time”: 426, “_securityState”: “secure”, “serverIPAddress”: “40.126.1.165”, “connection”: “443” }, { “pageref”: “page_3”, “startedDateTime”: “2019-11-09T20:04:53.489+01:00”, “request”: { “bodySize”: 0, “method”: “GET”,

There is plenty of guff here, but a picture emerges.

The first call

https://login.microsoftonline.com/navnob2c.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1a_idporten&response_type=code&client_id=45104d6a-f5bc-4e8c-b352-4bbfc9381f25&redirect_uri=https%3A%2F%2Floginservice.nav.no%2Fcallback&scope=openid+offline_access+45104d6a-f5bc-4e8c-b352-4bbfc9381f25&state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&nonce=HLPaFgxW368_-E6Rj5L6D0iT4yufUO6kydE21oT3QJE&level=Level3″

which redirects to

https://oidc.difi.no/idporten-oidc-provider/authorize?client_id=oidc_nav&redirect_uri=https%3a%2f%2flogin.microsoftonline.com%2fte%2fnavnob2c.onmicrosoft.com%2foauth2%2fauthresp&response_type=code&scope=openid&response_mode=form_post&nonce=%2fC9sCl2kb7TZMD4tPS1%2fAg%3d%3d&acr_values=Level3&state=StateProperties%3deyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0

On the way back
https://login.microsoftonline.com/te/navnob2c.onmicrosoft.com/oauth2/authresp
which redirects to

https://loginservice.nav.no/callback?state=_JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&code=eyJraWQiOiJhT05QQk9fWDV0bzNIX2tsMllSTjRFRGdUMkVvQ201bmNCNlB1MEhOSlNJIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6IjEuMCJ9.b5lGSnVxsolX3Wa1gqGh5qqhm8upQh3laxBhYbqC2FixHYog53-6ilhTGxNevcqYL-gFih4xwTqNYJuEH7ux-eRr8YoUcv7Mv1TO3U-VtddA1O7ZMF6mbu3L8DcOFqHR7OahL4j_QVZm9z-gAYFl_yZvAMmQ4Selk_uKAzvwLkjE57u4S61nArLSknOJDV8XwpO4Ow_iicpL5RC_dr4jaLGH6WH6bMgLrtQ2uNfb2KhYQYQhkTmkYjqgx7fgPbqddz0OOCF8PUIEL7sKpl1-d0Uv75iAqXUJofZlFVDcDfBoO6noxaLVkWmNjWvHWmKHbHImmOTD__XtExAMoMK8wg.LJS-OSzaHhkhVERs.LCBP0FbMPn9OKkej4fmYlN9fj-cgwYPCKSulz96qY06wrmMOFokm5Iies7nsPsS2SD5WJGw-D4vlso-ac-yjHqNI_s-KequNz5XiNjMS_gaJYh19bfivmKJmCxOJjrobA95FzBAkJaOHezJNDWP_tlfB-0wzD8Y5JYCYJGw3CXvhlQDtNH3vAprgkEtA9sHxzoz_ejzZwT2Xrb5z2aI8RUJI1Y2WDHLKo8uXfkROJDAajYtWKIm2LcaFwdtnm90kXGHFB7tIRF76L8sOgc2IuK6l3UBlFpJcsaPeY-bvGK9rMotjSKqZjAiIs_OTkcpL_GPNbpyiicjQWdVFLLf51ivWlHvdADrCxDH20yLWu6GiYZMHUW4YXCDODhmrZx4LmEp35v_1Wpji-1HeKH3X7gPgZXVjhL9bK0ApnyCsUy6Vi-P5KyEy8Ne6UV0UKQZQjl58SoV67UKrabt44Wr9CDvYHCQwBh4WwJ-3pw2lF4-FbwXYE9A3ssdbAI5sM9M8XHAt537KRWTgaXw1xmrEQ3VQ8q6nNBIUhEKdtr43-q8NULpc2Yh8Q8fFPhBaUbtYSEeRKl-vrpiKI2yB4deG8bz6dwtgCiHdQ9R81hPCloAqNgUHzIl0roZkyu1acw.BDHTKPyICH1GZs9SIr-Xqg

This is an Oauth transaction where Microsoft is the identity provider for NAV. The result is a JWT token passed from Microsoft to NAV. Microsoft in turn calls on Difi to establish the user’s identity.
At first look, Microsoft passes back more information than it receives. The call back from Difi to MS is a POST, but it contains only two parameters

MS to Difi

client_id: oidc_nav
redirect_uri: https%3a%2f%2flogin.microsoftonline.com%2fte%2fnavnob2c.onmicrosoft.com%2foauth2%2fauthresp
response_type: code
scope: openid
response_mode: form_post
nonce: %2fC9sCl2kb7TZMD4tPS1%2fAg%3d%3d
acr_values: Level3
state: StateProperties%3deyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0

Difi to MS
code: MryzERHWMbxfjnvLYEiJpw7_ojLZ4qKowtDMHytb7I0
state: StateProperties=eyJTSUQiOiJ4LW1zLWNwaW0tcmM6MTQ4MTE4YzctODc3MC00MzQ2LTkwMGEtNTkwYWVkZmI5MThlIiwiVElEIjoiZmE2OGVkYzctZTg0OS00MzA2LThmZmItOTExYmYwMjkzZDZmIn0

MS to NAV
state: _JTWomMWhyZw6bZifoPHgUw-7OccK-hV9BKi1VaMQYk&code=eyJraWQiOiJhT05QQk9fWDV0bzNIX2tsMllSTjRFRGdUMkVvQ201bmNCNlB1MEhOSlNJIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6IjEuMCJ9.b5lGSnVxsolX3Wa1gqGh5qqhm8upQh3laxBhYbqC2FixHYog53-6ilhTGxNevcqYL-gFih4xwTqNYJuEH7ux-eRr8YoUcv7Mv1TO3U-VtddA1O7ZMF6mbu3L8DcOFqHR7OahL4j_QVZm9z-gAYFl_yZvAMmQ4Selk_uKAzvwLkjE57u4S61nArLSknOJDV8XwpO4Ow_iicpL5RC_dr4jaLGH6WH6bMgLrtQ2uNfb2KhYQYQhkTmkYjqgx7fgPbqddz0OOCF8PUIEL7sKpl1-d0Uv75iAqXUJofZlFVDcDfBoO6noxaLVkWmNjWvHWmKHbHImmOTD__XtExAMoMK8wg.LJS-OSzaHhkhVERs.LCBP0FbMPn9OKkej4fmYlN9fj-cgwYPCKSulz96qY06wrmMOFokm5Iies7nsPsS2SD5WJGw-D4vlso-ac-yjHqNI_s-KequNz5XiNjMS_gaJYh19bfivmKJmCxOJjrobA95FzBAkJaOHezJNDWP_tlfB-0wzD8Y5JYCYJGw3CXvhlQDtNH3vAprgkEtA9sHxzoz_ejzZwT2Xrb5z2aI8RUJI1Y2WDHLKo8uXfkROJDAajYtWKIm2LcaFwdtnm90kXGHFB7tIRF76L8sOgc2IuK6l3UBlFpJcsaPeY-bvGK9rMotjSKqZjAiIs_OTkcpL_GPNbpyiicjQWdVFLLf51ivWlHvdADrCxDH20yLWu6GiYZMHUW4YXCDODhmrZx4LmEp35v_1Wpji-1HeKH3X7gPgZXVjhL9bK0ApnyCsUy6Vi-P5KyEy8Ne6UV0UKQZQjl58SoV67UKrabt44Wr9CDvYHCQwBh4WwJ-3pw2lF4-FbwXYE9A3ssdbAI5sM9M8XHAt537KRWTgaXw1xmrEQ3VQ8q6nNBIUhEKdtr43-q8NULpc2Yh8Q8fFPhBaUbtYSEeRKl-vrpiKI2yB4deG8bz6dwtgCiHdQ9R81hPCloAqNgUHzIl0roZkyu1acw.BDHTKPyICH1GZs9SIr-Xqg

Being bigger is not neccesarily important: the JSON in a JWT token contains metadata. And in this case the JWT token is also encrypted.
However, the stateproperties passed back and forth between MS and Difi is not

It contains only the base64 encoded JSON
{“SID”:”x-ms-cpim-rc:148118c7-8770-4346-900a-590aedfb918e”,”TID”:”fa68edc7-e849-4306-8ffb-911bf0293d6f”}

If this is not encrypted, why is the JWT encrypted ? Either both or neither to my mind. The question is not confidentiality here, these are merely temprary reference values, but rather integrity. In this case I’d say both should have been encrypted. It seems the connection between MS and Difi is not robust.
If MS maintains state such that the authorization token and stateproperties received from Difi is matched with the statepropertes sent to Difi – then fine. If not, then not fine at all.

What is in the JWT ? It is too big for only metadata. And nothing about the user was passed from Difi to MS, so if the JWT contain user info, where did it come from?

But this begs a larger question. Why is microsoftonline.com involved at all ?
Because it is not necessary, obviously. Another example from another government service. They set up a much tighter login, still using the same federation partner Bankid.

Similar domain name hit histogram as above

52 idporten.difi.no
20 anmeldelse.pub.politiet.no
14 csfe.bankid.no
3 oidc.difi.no

Clearly a very much tighter operation here. Since the government federation broker is difi.no here to the minimum number of domains, including the ID-provider, is 3. A first look a total of four domains involved must be considered a solid piece of work. Everything has a dot-no domain. So GDPR should not be a concern.
But perhaps the details show some things slipping through where it shouldn’t.

“url”: “https://anmeldelse.pub.politiet.no/webjars/anmeldelse/skjema.html?type=sykkel”, “httpVersion”: “HTTP/2.0”, “headers”: [ { “name”: “Host”, “value”: “anmeldelse.pub.politiet.no” }, { “name”: “User-Agent”, “value”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0” }, { “name”: “Accept”, “value”: “text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8” }, { “name”: “Accept-Language”, “value”: “en-GB,en;q=0.5” }, { “name”: “Accept-Encoding”, “value”: “gzip, deflate, br” }, { “name”: “DNT”, “value”: “1” }, { “name”: “Connection”, “value”: “keep-alive” }, { “name”: “Referer”, “value”: “https://anmeldelse.pub.politiet.no/webjars/anmeldelse/index.html?type=sykkel” }, { “name”: “Cookie”, “value”: “XSRF-TOKEN=a308a8d1-ffa5-4591-9c1e-6d2e0af98e8c; ApplicationGatewayAffinity=218f983d4932882bd40a98762d95d965a6cdbef861a68362433bb959d0589ee0” }, { “name”: “Upgrade-Insecure-Requests”, “value”: “1” }, { “name”: “TE”, “value”: “Trailers” } ], “cookies”: [ { “name”: “XSRF-TOKEN”, “value”: “a308a8d1-ffa5-4591-9c1e-6d2e0af98e8c” }, { “name”: “ApplicationGatewayAffinity”, “value”: “218f983d4932882bd40a98762d95d965a6cdbef861a68362433bb959d0589ee0” } ], “queryString”: [ { “name”: “type”, “value”: “sykkel” } ], “headersSize”: 627 }, “response”: { “status”: 302, “statusText”: “Found”, “httpVersion”: “HTTP/2.0”, “headers”: [ { “name”: “cache-control”, “value”: “no-cache, no-store, max-age=0, must-revalidate” }, { “name”: “pragma”, “value”: “no-cache” }, { “name”: “expires”, “value”: “0” }, { “name”: “location”, “value”: “https://anmeldelse.pub.politiet.no/oauth2/authorization/idporten” }, { “name”: “set-cookie”, “value”: “JSESSIONID=53848E5BB6B11F125EB7524836844FEB; Path=/; Secure; HttpOnly” }, { “name”: “x-content-type-options”, “value”: “nosniff” }, { “name”: “x-xss-protection”, “value”: “1; mode=block” }, { “name”: “strict-transport-security”, “value”: “max-age=1036800 ; includeSubDomains” }, { “name”: “x-frame-options”, “value”: “DENY” }, { “name”: “content-security-policy”, “value”: “default-src ‘self’;connect-src ‘self’ https://*.difi.no;style-src ‘self’ ‘unsafe-inline’;img-src ‘self’ data:” }, { “name”: “date”, “value”: “Sun, 05 Jan 2020 10:33:29 GMT” }, { “name”: “content-length”, “value”: “0” }, { “name”: “X-Firefox-Spdy”, “value”: “h2” } ], “cookies”: [ { “name”: “JSESSIONID”, “value”: “53848E5BB6B11F125EB7524836844FEB” } ], “content”: { “mimeType”: “text/html; charset=UTF-8”, “size”: 15043, “comment”: “Response bodies are not included.” }, “redirectURL”: “https://anmeldelse.pub.politiet.no/oauth2/authorization/idporten”, “headersSize”: 639, “bodySize”: 15682 }, “cache”: {}, “timings”: { “blocked”: 0, “dns”: 0, “connect”: 0, “ssl”: 0, “send”: 0, “wait”: 69, “receive”: 0 }, “time”: 69, “_securityState”: “secure”, “serverIPAddress”: “40.85.119.201”, “connection”: “443” }, { “pageref”: “page_1”, “startedDateTime”: “2020-01-05T11:33:28.807+01:00”, “request”: { “bodySize”: 0, “method”: “GET”,

“url”: “https://anmeldelse.pub.politiet.no/oauth2/authorization/idporten”, “httpVersion”: “HTTP/2.0”, “headers”: [ { “name”: “Host”, “value”: “anmeldelse.pub.politiet.no” }, { “name”: “User-Agent”, “value”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0” }, { “name”: “Accept”, “value”: “text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8” }, { “name”: “Accept-Language”, “value”: “en-GB,en;q=0.5” }, { “name”: “Accept-Encoding”, “value”: “gzip, deflate, br” }, { “name”: “Referer”, “value”: “https://anmeldelse.pub.politiet.no/webjars/anmeldelse/index.html?type=sykkel” }, { “name”: “DNT”, “value”: “1” }, { “name”: “Connection”, “value”: “keep-alive” }, { “name”: “Cookie”, “value”: “XSRF-TOKEN=a308a8d1-ffa5-4591-9c1e-6d2e0af98e8c; ApplicationGatewayAffinity=218f983d4932882bd40a98762d95d965a6cdbef861a68362433bb959d0589ee0; JSESSIONID=53848E5BB6B11F125EB7524836844FEB” }, { “name”: “Upgrade-Insecure-Requests”, “value”: “1” }, { “name”: “TE”, “value”: “Trailers” } ], “cookies”: [ { “name”: “XSRF-TOKEN”, “value”: “a308a8d1-ffa5-4591-9c1e-6d2e0af98e8c” }, { “name”: “ApplicationGatewayAffinity”, “value”: “218f983d4932882bd40a98762d95d965a6cdbef861a68362433bb959d0589ee0” }, { “name”: “JSESSIONID”, “value”: “53848E5BB6B11F125EB7524836844FEB” } ], “queryString”: [], “headersSize”: 659 }, “response”: { “status”: 302, “statusText”: “Found”, “httpVersion”: “HTTP/2.0”, “headers”: [ { “name”: “cache-control”, “value”: “no-cache, no-store, max-age=0, must-revalidate” }, { “name”: “pragma”, “value”: “no-cache” }, { “name”: “expires”, “value”: “0” }, { “name”: “location”, “value”: “https://oidc.difi.no/idporten-oidc-provider/authorize?response_type=code&client_id=d57e1963-4d31-418d-a4aa-85329c0a5971&scope=openid%20profile&state=kzSBcqvpGyGRUMEQ8sejiIJYcQxzTslzRfW4lG1_t7U%3D&redirect_uri=https://anmeldelse.pub.politiet.no/login/oauth2/code/idporten&nonce=GAYtjS6wlIvJ0veysvHFP0Vs3Mxyy1_sywqQq1X-IfI” }, { “name”: “x-content-type-options”, “value”: “nosniff” }, { “name”: “x-xss-protection”, “value”: “1; mode=block” }, { “name”: “strict-transport-security”, “value”: “max-age=1036800 ; includeSubDomains” }, { “name”: “x-frame-options”, “value”: “DENY” }, { “name”: “content-security-policy”, “value”: “default-src ‘self’;connect-src ‘self’ https://*.difi.no;style-src ‘self’ ‘unsafe-inline’;img-src ‘self’ data:” }, { “name”: “date”, “value”: “Sun, 05 Jan 2020 10:33:29 GMT” }, { “name”: “content-length”, “value”: “0” }, { “name”: “X-Firefox-Spdy”, “value”: “h2” } ], “cookies”: [], “content”: { “mimeType”: “text/html; charset=UTF-8”, “size”: 15043, “comment”: “Response bodies are not included.” }, “redirectURL”: “https://oidc.difi.no/idporten-oidc-provider/authorize?response_type=code&client_id=d57e1963-4d31-418d-a4aa-85329c0a5971&scope=openid%20profile&state=kzSBcqvpGyGRUMEQ8sejiIJYcQxzTslzRfW4lG1_t7U%3D&redirect_uri=https://anmeldelse.pub.politiet.no/login/oauth2/code/idporten&nonce=GAYtjS6wlIvJ0veysvHFP0Vs3Mxyy1_sywqQq1X-IfI”, “headersSize”: 812, “bodySize”: 15855 }, “cache”: {}, “timings”: { “blocked”: 0, “dns”: 2, “connect”: 0, “ssl”: 0, “send”: 0, “wait”: 53, “receive”: 0 }, “time”: 55, “_securityState”: “secure”, “serverIPAddress”: “40.85.119.201”, “connection”: “443” }, { “pageref”: “page_1”, “startedDateTime”: “2020-01-05T11:33:28.860+01:00”, “request”: { “bodySize”: 0, “method”: “GET”,

“url”: “https://oidc.difi.no/idporten-oidc-provider/authorize?response_type=code&client_id=d57e1963-4d31-418d-a4aa-85329c0a5971&scope=openid%20profile&state=kzSBcqvpGyGRUMEQ8sejiIJYcQxzTslzRfW4lG1_t7U%3D&redirect_uri=https://anmeldelse.pub.politiet.no/login/oauth2/code/idporten&nonce=GAYtjS6wlIvJ0veysvHFP0Vs3Mxyy1_sywqQq1X-IfI”

“Location”: “https://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?SAMLRequest=nZRNj9owEIbv%2FRWR7yGfQLBIVix0VaRtoZDtoZfK2JPFUmKntsOy%2F75OIDSVWg49RbJn3nk9z0zmD%2BeqdE6gNJciRcHIRw4IKhkXryl6yZ%2FcBD1kH%2BaaVGVY40VjjmIHPxvQxlloDcrYvKUUuqlA7UGdOIWX3XOKjsbUGnue5IyOGC%2F4SEgcx5HHWS2VAeG2N26t5IkzUB7pxehVDDkrW4QLYjpnvV6f3mt6sgahtfT2%2B80OGFdAjVeBIYuSE%2B0JqV6hDbN5MXKepKLQPSJFBSk1IGe9StGPSciSMKax74eH6XhSRAkNWZQExWE2IYxENkzrBtZCGyJMikI%2F9F0%2FcP1xHvg4inA4GyXT8XfkbJU0ksrykYtLDxslsCSaayxIBRobiveLz884HPn4cAnS%2BFOeb93tZp8j51vPImxZWDpC40v372vV18Iou8DCnWM1VLgvcCOAsiG0uTeUy%2BYVwx%2FPFkBrUl%2FVK3ZfuuXBiCHW20Y8wpGUxabI2HgKwWwSuTGLAjcOEuaSmBA3GUfhjPpkPJsGc2%2BQMPf%2BKJ71U%2FnFFlyvtrLk9N1ZlKV8WyogBlJkVAMd9YqY%2BxbbE87cogvFdQtB20IGOfttq%2F%2B1IaVtCKgUDbuDvJuL61oA6%2BbL7oSBs3GWsqqJ4rolWnHBq6a6ERoGLkvb%2Fx0U%2F8XrbhjFtNW2x1v7eZOKtTNq1wRYrojQ7T71kP%2FmKLte%2FuOFv6%2BHP4fsFw%3D%3D&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=WhMFeI5wORYVEVNcqzjS6AYN8jcMnpMPfARFCR0jl2X%2F80HKB55L7nUEl8BCAUe48oOOVfy7tFburXcqMfFPR%2FLPiikniI1m7a%2Fy0hucr%2FGkZMOChi%2Bf%2BHwHA3GAj9kedHgy%2BCO5zp%2FS3EtQ9LQ5WIA3zkr%2BQQ%2BElV41zOIBVAotNnM9FG7M39tCwU2q%2BnCHZ1u4zrZQNtDy%2BEmucmcdWrSv7RIZoCToJ3qE%2F7BeTWPP9xLdKap9CmVe7j0i52%2F23TLK0oQxJ2UfbMEtf5R89FGZ3tMzP3e5297Etbs6vsq9vUjUzkyik6POPQBa46w6mmvRjPM3ikZSpN1pUP751A%3D%3D&locale=nb

“url”: “https://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?SAMLRequest=nZRNj9owEIbv%2FRWR7yGfQLBIVix0VaRtoZDtoZfK2JPFUmKntsOy%2F75OIDSVWg49RbJn3nk9z0zmD%2BeqdE6gNJciRcHIRw4IKhkXryl6yZ%2FcBD1kH%2BaaVGVY40VjjmIHPxvQxlloDcrYvKUUuqlA7UGdOIWX3XOKjsbUGnue5IyOGC%2F4SEgcx5HHWS2VAeG2N26t5IkzUB7pxehVDDkrW4QLYjpnvV6f3mt6sgahtfT2%2B80OGFdAjVeBIYuSE%2B0JqV6hDbN5MXKepKLQPSJFBSk1IGe9StGPSciSMKax74eH6XhSRAkNWZQExWE2IYxENkzrBtZCGyJMikI%2F9F0%2FcP1xHvg4inA4GyXT8XfkbJU0ksrykYtLDxslsCSaayxIBRobiveLz884HPn4cAnS%2BFOeb93tZp8j51vPImxZWDpC40v372vV18Iou8DCnWM1VLgvcCOAsiG0uTeUy%2BYVwx%2FPFkBrUl%2FVK3ZfuuXBiCHW20Y8wpGUxabI2HgKwWwSuTGLAjcOEuaSmBA3GUfhjPpkPJsGc2%2BQMPf%2BKJ71U%2FnFFlyvtrLk9N1ZlKV8WyogBlJkVAMd9YqY%2BxbbE87cogvFdQtB20IGOfttq%2F%2B1IaVtCKgUDbuDvJuL61oA6%2BbL7oSBs3GWsqqJ4rolWnHBq6a6ERoGLkvb%2Fx0U%2F8XrbhjFtNW2x1v7eZOKtTNq1wRYrojQ7T71kP%2FmKLte%2FuOFv6%2BHP4fsFw%3D%3D&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=WhMFeI5wORYVEVNcqzjS6AYN8jcMnpMPfARFCR0jl2X%2F80HKB55L7nUEl8BCAUe48oOOVfy7tFburXcqMfFPR%2FLPiikniI1m7a%2Fy0hucr%2FGkZMOChi%2Bf%2BHwHA3GAj9kedHgy%2BCO5zp%2FS3EtQ9LQ5WIA3zkr%2BQQ%2BElV41zOIBVAotNnM9FG7M39tCwU2q%2BnCHZ1u4zrZQNtDy%2BEmucmcdWrSv7RIZoCToJ3qE%2F7BeTWPP9xLdKap9CmVe7j0i52%2F23TLK0oQxJ2UfbMEtf5R89FGZ3tMzP3e5297Etbs6vsq9vUjUzkyik6POPQBa46w6mmvRjPM3ikZSpN1pUP751A%3D%3D&locale=nb”

“Location”: “https://idporten.difi.no:443/opensso/UI/Login?realm=/norge.no&spEntityID=oidc.difi.no&service=IDPortenLevel3List&goto=http://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID%3D_62d824c4002b756f38c2d381fb96ada3%26index%3Dnull%26acsURL%3Dhttps://oidc.difi.no:443/idporten-oidc-provider/assertionconsumer%26spEntityID%3Doidc.difi.no%26binding%3Durn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST

“url”: “https://idporten.difi.no/opensso/bidresponse”

“Location”: “https://idporten.difi.no:443/opensso/UI/Login?realm=norge.no&ForceAuth=&gx_charset=UTF-8&locale=nb&goto=http://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID=_62d824c4002b756f38c2d381fb96ada3&service=BankIDResponse

“url”: “https://idporten.difi.no/opensso/UI/Login?realm=norge.no&ForceAuth=&gx_charset=UTF-8&locale=nb&goto=http://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID=_62d824c4002b756f38c2d381fb96ada3&service=BankIDResponse”

“Location”: “https://idporten.difi.no/opensso/SSORedirect/metaAlias/norge.no/idp4?ReqID=_62d824c4002b756f38c2d381fb96ada3

“url”: “https://oidc.difi.no/idporten-oidc-provider/assertionconsumer”

“Location”: “https://oidc.difi.no/idporten-oidc-provider/consent?mid=_62d824c4002b756f38c2d381fb96ada3

“url”: “https://oidc.difi.no/idporten-oidc-provider/consent?mid=_62d824c4002b756f38c2d381fb96ada3”

“Location”: “https://anmeldelse.pub.politiet.no/login/oauth2/code/idporten?code=gtJFV1p5nKatkV7FyXkU02jhcfPFgEoz47k4q7PnCxY&state=kzSBcqvpGyGRUMEQ8sejiIJYcQxzTslzRfW4lG1_t7U%3D

“url”: “https://anmeldelse.pub.politiet.no/login/oauth2/code/idporten?code=gtJFV1p5nKatkV7FyXkU02jhcfPFgEoz47k4q7PnCxY&state=kzSBcqvpGyGRUMEQ8sejiIJYcQxzTslzRfW4lG1_t7U%3D”, “httpVersion”: “HTTP/2.0”, “headers”: [ { “name”: “Host”, “value”: “anmeldelse.pub.politiet.no” }, { “name”: “User-Agent”, “value”: “Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0” }, { “name”: “Accept”, “value”: “text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8” }, { “name”: “Accept-Language”, “value”: “en-GB,en;q=0.5” }, { “name”: “Accept-Encoding”, “value”: “gzip, deflate, br” }, { “name”: “Referer”, “value”: “https://idporten.difi.no/” }, { “name”: “DNT”, “value”: “1” }, { “name”: “Connection”, “value”: “keep-alive” }, { “name”: “Cookie”, “value”: “XSRF-TOKEN=a308a8d1-ffa5-4591-9c1e-6d2e0af98e8c; ApplicationGatewayAffinity=218f983d4932882bd40a98762d95d965a6cdbef861a68362433bb959d0589ee0; JSESSIONID=53848E5BB6B11F125EB7524836844FEB” }, { “name”: “Upgrade-Insecure-Requests”, “value”: “1” }, { “name”: “TE”, “value”: “Trailers” } ], “cookies”: [ { “name”: “XSRF-TOKEN”, “value”: “a308a8d1-ffa5-4591-9c1e-6d2e0af98e8c” }, { “name”: “ApplicationGatewayAffinity”, “value”: “218f983d4932882bd40a98762d95d965a6cdbef861a68362433bb959d0589ee0” }, { “name”: “JSESSIONID”, “value”: “53848E5BB6B11F125EB7524836844FEB” } ], “queryString”: [ { “name”: “code”, “value”: “gtJFV1p5nKatkV7FyXkU02jhcfPFgEoz47k4q7PnCxY” }, { “name”: “state”, “value”: “kzSBcqvpGyGRUMEQ8sejiIJYcQxzTslzRfW4lG1_t7U=” } ], “headersSize”: 707 }, “response”: { “status”: 302, “statusText”: “Found”, “httpVersion”: “HTTP/2.0”, “headers”: [ { “name”: “cache-control”, “value”: “no-cache, no-store, max-age=0, must-revalidate” }, { “name”: “pragma”, “value”: “no-cache” }, { “name”: “expires”, “value”: “0” }, { “name”: “location”, “value”: “https://anmeldelse.pub.politiet.no/webjars/anmeldelse/skjema.html?type=sykkel” }, { “name”: “set-cookie”, “value”: “JSESSIONID=93798A700538A6625D75042F2816EB6B; Path=/; Secure; HttpOnly” }, { “name”: “set-cookie”, “value”: “XSRF-TOKEN=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; Secure” }, { “name”: “set-cookie”, “value”: “XSRF-TOKEN=76c82040-160f-471c-a4e0-4d85e9c6b361; Path=/; Secure” }, { “name”: “x-content-type-options”, “value”: “nosniff” }, { “name”: “x-xss-protection”, “value”: “1; mode=block” }, { “name”: “strict-transport-security”, “value”: “max-age=1036800 ; includeSubDomains” }, { “name”: “x-frame-options”, “value”: “DENY” }, { “name”: “content-security-policy”, “value”: “default-src ‘self’;connect-src ‘self’ https://*.difi.no;style-src ‘self’ ‘unsafe-inline’;img-src ‘self’ data:” }, { “name”: “date”, “value”: “Sun, 05 Jan 2020 10:34:20 GMT” }, { “name”: “content-length”, “value”: “0” }, { “name”: “X-Firefox-Spdy”, “value”: “h2” } ], “cookies”: [ { “name”: “JSESSIONID”, “value”: “93798A700538A6625D75042F2816EB6B” }, { “name”: “XSRF-TOKEN”, “value”: “” }, { “name”: “XSRF-TOKEN”, “value”: “76c82040-160f-471c-a4e0-4d85e9c6b361” } ], “content”: { “mimeType”: “text/html”, “size”: 724, “comment”: “Response bodies are not included.” }, “redirectURL”: “https://anmeldelse.pub.politiet.no/webjars/anmeldelse/skjema.html?type=sykkel”, “headersSize”: 794, “bodySize”: 1362 }, “cache”: {}, “timings”: { “blocked”: 0, “dns”: 1, “connect”: 0, “ssl”: 0, “send”: 0, “wait”: 284, “receive”: 0 }, “time”: 285, “_securityState”: “secure”, “serverIPAddress”: “40.85.119.201”, “connection”: “443” }, { “pageref”: “page_1”, “startedDateTime”: “2020-01-05T11:34:19.748+01:00”, “request”: { “bodySize”: 0, “method”: “GET”,

Both Oauth and SAML are involed, but there is nothing wrong with that. For my money SAML is more robust (let’s hear it for signed and encrypted tokens contaning usefull data!), but OAuth is of course newer and leaner if you think byte count in HTTP traffic matters.

Token based API access control has a critical flaw

I’ve written on this subject before. I come back to the subject because I keep coming across this problem. Granted where or not it is a problem depends on how you look at things. My view is from the point of view of robustness and fail-safety.

I work with programmers quite a bit and theirs is to deliver functionality out the door. Which is understandable: that is what they are measured on.

Then I come along later and try to track down a problem. Over privileged service accounts which is what these API access tokens amount to is a perennial problem. Leaving aside for the moment the security aspect of it. A service account and an API access token can be poorly implemented in two main ways. Be given too much access privileges, let’s call that a Type 1 fault; and be shared by too many different entities, call that Type 2. I’ve seen plenty of both. Okta is a good(bad) example of the former. Their SaaS REST API only grants one kind of access token. To everything.  Type 1 fault as bad as can be.

Programmers using the API for Okta can then keep reusing the same access token – it is just a text string after all – to any extent rather than going to the rigmarole of issuing another. Yes, it happens. A lot. Type 2 fault. The API access tokens are usually valid for a long time since they are meant to be used by other applications, hence the service account equivalence, but can be selectively revoked and at least in Okta there is good overview of currently valid tokens. But not what has been going on with them and what they have been used for.

In Unix/Linux these API tokens are like having multiple root accounts that have been shared with people you do not know and being used for unknown things. No one would call that a satisfactory state of affairs on a *x server system. But it is rarely expressed in those terms.

The root account comparison is apt. On unix -like systems the root user is not subject to OS-level access control. Access is unlimited. Switching to any other user however souped-up, is better. But it involves actually implementing some access control: groups and permissions in a unix-like system. Which can be laborious – and worse, error prone. So let’s just give it root – at least it will work.

Yes, laziness. The malicious user/intruders best friend.  API access tokens are employed on great many platforms but since we call them API access tokens rather than user/service accounts, little or no scrutiny is ever applied to them.

Now we have these API tokens with good-like system powers. Revocable, sure, but does that ever happen ?

Funny symptoms on OpenAM when session handling is under strain.

Of late I have been examining  an intermittent error situation at a large OpenAM implementation. Several aspects of the implementation are not in accordance with the recommendation of the vendor, or even good practice. But that has afforded some very good learning opportunities. As is often the case when straying from the preferred path.

The deployment there are four OpenAM instances and four peer-to-peer replicated OpenDJ instances for data storage.

OpenAM keeps policy, configuration and session information in a directory. OpenDJ in this scenario. It is for obvious reasons recommended to keep the session store (it takes more load and does not need a backup) separate from the policy and configuration store.

An early clue was that the error conditions where resolvable with restarts. Clearly this was not fundamentally a policy matter. Policies persist across restarts. Sessions however, do not. Following up on this it was discovered that the sessions store and policy store where collocated.

OpenAM has caching on session token validation operations. So there would be no need to ask the directory everytime a session token is to be validated. But this is an object cache, not a search cache. So the session object can be cached on the OpenAM instance but if there is an attempt to validate a non-existent token, that attempt would result in a search against the underlying session object store. Every time. Examination of the search logs on the object store revealed that between 12% and 40% of token search operations were for tokens that did not exist.

It gets worse. Since the customer had declined to implement stickyness on the load balancer in front of the multiple OpenAM instances, users were sprayed across all of them. This leads to an excessive number of session token modification operations. Quite a large number of them in fact; Many tokens were modified hundreds of times. And with all modifications replicated across all of the directory store instances, the load on the OpenDJ instances is considerable.

But wait, it gets worse still. Forgerock is quite adamant that there can be no load balancing going on between the OpenAM and directories used as session store. In this design there are four OpenDJ OpenDJ instances used for sessions store, one designated for each OpenAM instance. Should one OpenDJ instance become unavailable “it’s” OpenAM instance will use one of the others, but otherwise the OpenAM instance will used it’s designated OpenDJ instance for all session token operations.

One can of course argue about what constitutes load balancing but I think of it as being chiefly about load distribution, with or with out stickyness. This design I would describe the OpenAM to OpenDJ connection to load balanced with permanent stickyness.

Does this matter ? In a replicated environment all the OpenDJ instances will be equal. Ideally, no. But not always. There will always be some replication delay. The problem here was the users being distributed across all OpenAM instances. Meaning that the same token operation could arrive at two, or more, different OpenAM instances practically simultaneously. Replication is fast in a good network and with good indexing. But it does not take zero time. If different OpenAM instances uses different OpenDJ instances as session token store, there will be errors. Probably not many, but ones likely to increase in frequency with increasing system load.

Ok. How to determine this. First: have plenty of logging on the OpenDJs. The search request for session tokens are easy to identity in the OpenDJ access log. They are base-level searches and therefore simple to extract reliably with an egrep statement. The same with failures to find a token. In fact directly related to the base level searches for tokens. A base level search when the base object does not exist produces an error to that effect. In this case the access log clearly states that the session token object is not present. Very convenient. And egrep-able.

So it is easy the get a list of tokens being searched for and which ones were not found. Extract these list from all OpenDJ instances within the same time period – say one hour. And determine if there where any failed token searches on any instance that succeeded on any of the others. There were.

 

We all gripe about vendor documentation. And Forerock has had some doosies. But there is usually good advice in there. Don’t ignore it without very good reason backed up by observational data.

The short and sweet on OpenAM, play nice with your session handling.

true desktop Single Sign-on for any web based application ?… get out of here.

Single SIgn-on, SSO for short, is an an attractive but elusive thing. Log into to your dekstop PC and be signed in to all your other applications – be they local or remote.  Your cloud provided business applications: Office 365, Amazon Web Services. Your online news site: The Economist etc.  Without having to enter username and password again. This does sound attractive.

So much so that some have found it expedient to sell something as SSO which strictly speaking is only single-login. There are tools for propagating usernames and synchronizing users stores. But they don’t log you in when you need to. You still have to enter your username and password. This is not SSO, merely single provisioning. Helpful, but still a nuisance with repeated entering of login information. What we want is true Single Sign-on.

All those login names and passwords. If you consistently use only your email address (and always the same one) as user name. Perhaps even, incautiously use the same password everywhere. There is sheer nuisance of it all.  Which in and of it self is enough to make people use the same password everywhere. This makes corporate systems vulnerable. If someone has used a password in an external system and this system is compromised, and the password revealed. Well, the attacker now has a very good password first guess for further attacks. So SSO which obviates the practical need to unified login information, but particularly the re-use of passwords, is much needed.

Such solutions do exists. User federation happen in many ways. You can now sing in to many applications simply by using your login to Facebook. Microsoft provides ADFS which allows SSO to many applications in the Windows sphere, most particularly Office 365, from you Windows desktop. This is what we want SSO from the desktop, but without the limitations of ADFS. We want to be able to login anywhere, not just to places that have been configured for ADFS.

For the purposes of this article I’ll limit myself to Sing-on part – the actual loging in. This presupposes the existence of an account in the target system, leaving just-in-time-provisioning aside (but see here for exploration on the topic of account-less access) which I will assume is already in place. There are any number of ways to provision accounts. and to the extent that this is a one-time thing, not really much of a bother for the end user.

Recently I had occasion to explore the identity management tools from Okta (www.okta.com) which promised to deliver on this tall order.

 

What follows is not a complete “cook book.” but it will include all the steps I went through , in order, to put in place true desktop SSO using the Okta framework. Both for an application that accepts SAML based federated login: Here I picked Amazon Web Services, AWS, for the demonstration. And one that just has a username/password login: Here I selected The Economist.

 

 

The Okta SSO architecture contain the following components:

The user’s Windows desktop PC.

The Windows domain controller, DC, to which it subscribes,

The Okta server at https://<your domain>.okta.com, When your organization subscribed to Okta, this is set up for you with a sub-domain name of  your choosing. There is also an administration domain name of the form <yourdomain>-admin,okta.com,

The user’s browser,The SSO is only for web based applications. A browser is always employed in their access.

The plugin provided by Okta for that browser. The supported browsers are Internet Explorer, Mozilla Firefox, Google Chrome and Safari. This plugin is essential for populating login fields for non-SAML based logins.

Okta agent for the Windows DC. This agent must be installed somewhere in you corporate infrastructure on a Windows server with direct access to the DC. In this case it was installed directly on the DC.

Okta’s Integrated Windows Authentication, IWA, login application. This is a web applications that runs on an IIS instance in your corporate Windows server infrastructure. When your browser is configured to send Windows Authentication information to configured list of web domains, this application is on that list. This is the main way the ID with which you are authenticated to your desktop is collected by the Okta infrastructure. In this case it was installed directly on the DC.

 

First subscribe to Okta and login to the Okta admin interface. Okta has two free subscription options: A developers license with a limit on the number of different applications that can be connected to it, but last forever. Or a regular, “enterprise”, license with no limits on the applications but which is good (read: free) for only a 30-day trial period. In this example I have selected the “regular” one since the time limit is of no concern here.

After signup, an confirmation email is sent to you with the relevant login details.

Login to your corporate Okta page as the admin and go on to the administration interface (the “admin” button) From Setting- Download download the following:

The plugin for the browser(s) you are using. Keep the plugin install files for later installation in other browsers.

The AD agent installer.

SSO IWA Web App Installer

We won’t use the password synch agent in this exercise.

 

Create a serviceaccount for the AD Agent on the DC. I called it “OktaService” and placed in the root container in my “cloudworks” (dc=cloudworks,dc=demo) domain. This user must be granted permissions to log on as a service and as a batchjob. Plus the, for service accounts usual do not change at first logon and password never expires options.

Run the AD Agent installer (OktaADAgentSetup-3.2.1.exe) on a windows Server with access to the DC. I used Windows 2012 R2 which also hosts the DC, and this proved an excellent choice.

The installer ask for

Install path: accept defult

Domain: cloudwork.demo

Okta AD Agent service account: this will be used to access AD and is the one created earlier: “OktaService@cloudworks.demo” / password

Proxy Configuration: no

Register Okta AD Agent: The agent will be connected to the Okta infrastructure. specify you domain here. https.//cloudworks.okta.no  which means just ticking “Production” and entering “cloudwork” in the subdomain field.

A browser window opens and a HTTP connection is being made to Okta.  You are presnted wit ha login window where you specify the administrator login details for your corporate Okta account established above.

A question is presented: Okta AD Agent is requesting permission to access the Okta API. Click “Allow Access”.

Install the IWA application. This is a web application that we will install on an instance of IIS (version 8.5.9600 running locally on the DC. But you can install the IWA application on any existing instance of IIS you have handy.

The IWA installer request the details of the service account the IWA applicaiton will need to run (specifically the application pool set up in the IIS) I reused OktaService account from above.

Specify the okta subdomain to be used: “cloudworks”, in this example. Once again a browser windows is openen and a login windows to Okta is presented. Enter the administration login as per above.  “Okta Desktop SSO Agent is requesting permission to: access the entire Okta API” ? Click “Allow Access”.

Go to the IIS manager where the IWA is installed and make sure it really is running. It should have an Application pool names OktaIWA with the identity specified with the installer. One of the installed Sites should be IWA. Under it in the web tree you should see the directories: bin, certificate, conftemplate, docs, img, installerlog and tools.

Log in to the Okta admin console at https://<your subdomain>.okta.com which is https://cloudworks.okta.com

This login works on Internet Explorer but not on Firefox. initial front page

 

 

 

 

 

 

 

 

The message states that I do not have any applications. Which makes sense since I have not configured any yet. I logged in as the administrator so the little triangle next to my name is a drop-down menu with “Admin” on it. Selecting this brings me to the administration interface for our Okta implementation. This URL: https://cloudworks-admin.okta.com/admin/dashboard. which I will use directly from now on.

admin initial front page

 

 

 

 

 

 

 

 

 

 

Token-in-token, Agent-Principal model of authorization delegation

PAML tokens create portable authorization where the Enforcement point need not know either the Principal making the request or the Owner authorized to grant the request. But the Principal/user must be in direct contact with the enforcement point to establish, through a cryptographic handshake, ownership of the PAML token being used. In many scenarios this direct connection is undesirable, even impossible. The Principal can not have a direct connection to the enforcement point.
A medical records repository is a good example. Security rules prohibit direct access over the internet to such a repository. Intermediary entities, application servers, firewall and the like, are mandated gateways.
In effect someone or something, must act on behalf of the Principal with the Enforcement point: An Agent.

This can be effected by placing one PAML token inside another. This token-in-token functionality is described in detail below. Any number of tokens can be embedded inside one another. In some ways like a certificate chain.
As with a standard Agent-Principal model the Principal trusts the Agent to act in the way the Principal desires. But with PAML token the Principal can narrow the Agents latitude to the extent desired.

Definition of terms

The Principal. This is the person, or entity, on whose behalf the request is undertaken.

Agent. The person or entity carrying out the request task on behalf of the Principal.

Owner. The person or entity that decides if the Principal is entitled to have the request(s) undertaken.

Enforcer. Person or entity in control of the resource and handles the request from the Agent. The Enforcer accepts the PAML token for authorization decisions.

Here is a schematic of the flow

alt text

Agent-Principal use of PAML tokens

 

Explanation of steps
Step 1 Principal prepares a list of request, or logical super-set of requests, in an XML format document; and signs this list with the Principal’s own private key. The logical super-sets can include rules according to which the requests made by the agent should be evaluated. The Agent can only carry out request on this list or ones contained in super-sets on this list. The XML document can include XSLT operations to be applied at enforcement time to the request made by the Agent. With this XSLT the Principal can enforce additional limitations (such as timing or checking token revocation list) on the requests the Agent is making.

Creating (pseudo XML document)

<principal.signature><request.list/></principal.signature>

Using the private key used to sign the request list document and the public key that belong to it: engage in cryptographic handshake with Agent and through this, establish to the Agent’s satisfaction that the Principal is in possession of the private key used to sign the request list.
Pass the signed list to the Agent.

Step 2 Agent attaches own usage conditions to Principal’s signed request.

Creating

<principal.signature><request.list/></principal.signature><agents.usage.conditions/>

And sign with the Agent’s own private key.
Creating

<agent.signature><principal.signature><request.list/></principal.signature><agents.usage.conditions/></agent.signature>

Using the private key used to sign the document and the public key that belong to it: engage in cryptographic handshake with the Owner and through this, establish to the Owner’s satisfaction that the Agent is in possession of the private key used to sign the document.
Pass the signed document to the Owner.

Step 3
Owner attaches own usage conditions to Agent’s signed request.

Creating

<agent.signature><principal.signature><request.list/></principal.signature><agents.usage.conditions/></agent.signature><owners.usage.conditions/>

And sign with the Owners own private key. This is the same private key used to sign the resource the PAML token governs access to.

Creating

<owner.signature><agent.signature><principal.signature><request.list/></principal.signature><agents.usage.conditions/></agent.signature><owners.usage.conditions/></owner.signature>

The PAML token is now completed.
Return the PAML to the Agent.

Step 4
The Agent now has a PAML token providing authorized access to resources signed with the same private key that signed the token. The PAML token can be reused to the limits specified in the owner’s usage conditions. Typically these would at least include validity time periods.
The Agent can now make request to the Enforcer and have them be authorized by the token. The requests are on behalf of the Principal but do not have to be directly from the Principal.

The Agent engages in a cryptographic handshake with the Enforcer using the private key used to sign the document from the Principal and the public key that belong to it: engage in cryptographic handshake with the Enforcer and through this, establish to the Enforcer’s satisfaction that the Agent is in possession of the private key used to create agent signature in the PAML token document.
Passed one or more PAML tokens to the Enforcer.
Pass a request to the Enforcer.

Step 5

The Enforcer examines the PAML tokens it has received. The tokens are checked in the following way and order:
XML validation. Those containing invalid XML are discarded.
XML schema validation. Those containing improper XML are discarded.
Agents signature validation: Using the public key of the Agent established in the cryptographic handshake the agent signature in the token validated. Tokens failing this validation are discarded.
Remaining tokens are tokens the Agent is properly entitled to use.

Examine the request and match it to the request list part of the remaining PAML tokens.
Those token that do not govern the request are discarded. Meaning that the request list in the token(s) do(es) not have at least one match for the request.
The remaining PAML tokens, if any, both belong to the Agent and govern the request the Agent is making.
The Enforcer examines the resource the request is for and what, if any digital signature it bears. Only if the resource bears a signature that can be validated with the same public key that can also validate the owners signature on the PAML token, is the resource considered “in scope” for the request. These two signature validation are carried out using the public key of the owner included with owner’s signature on the PAML token. If both signatures can be successfully validated the request is authorized.

In step 5 we get the desired situation that a completely stand-alone enforcement point can make authorization decisions for agents acting on behalf of someone else, without having to know the identity of either of the parties. This gives obvious benefits in reduced complexity and  ease of deployment.

A Digital Commons

I was just reading Schneiers latest book “Data and Goliath” and was struck by a concept he mentioned: Commons. In the meaning of a digital commons, open and available for anyone to use; not under the control of any specific entity.
Usenet still exists but most online discussions are carried out on (corporate) entity owned websites and platforms. Entities that can and do exercise editorial control.
Anyone who has spent any time in newsgroups on Usenet know full well that it is the “wild west” out there. To the considerable chagrin of some.
A number of academic publishers have banded together to a repository for academic publications and named it (a) Digital Commons.
Not under any ones control and open to all. This satisfies some characteristics of a Common.
But going beyond publication of static documents, what is there. In a common there were many different activities possible: pasturing animals, gathering firewood and food stuffs. Perhaps a digital commons should allow for something more than making static files available to the public. Something interactive, something with some logic – i.e code.

Steganographic applications

Steganography is the practice of concealing something in something else. For instance hiding a text message inside a larger body of text. There is no cryptography. The security of the message, such as it is, is in the form of obscurity. That may be enough. Cryptography is computational expensive and required management of encryption keys. And it is no more secure that the keys employed. It appears that the better cryptographic algorithms are quite good and attacks tend to focus on the keys.
Attacking steganography would be different. Rather than asking Where is the key, one would ask is there anything there at all ?
There are applications for conducting steganography. Capable of embedding a message inside an image for example. But this is not about conducting steganography.

What I am after here is for application itself to be steganographic. To conceal the application, not inside another application, like a trojan, but altogether.

What would it mean for an application itself to steganographic.

Imagine an application as a book. And using an application as equivalent of reading a book from cover to cover.
Lets further imagine that we cut the the spine of a number of books and shuffle the loose pages together like so many decks of cards. Assuming uniformity of paper quality and page size, layout and font, and no metadata on page – having a loose page tells you little about which book it was from. Or if it came from any book at all.
If you have access to the full text of the original books that were shuffled together, you could do a text comparison and quickly identify which book the page came from. But in the absence of that there would be little to go on. Analyzing the text on the pages would yield some clues and more or less probable guesses could be made. Particularly if the books had comparatively few pages, i.e. if any one page contained a large fraction of the complete text.
The obfuscation could be further improved by cutting the pages up into individual lines of text.
Identifying a line as belonging to only one particular book would be difficult in many cases.

On a side note: what difference does it make cutting the pages up along the lines or across them, for the purposes of putting back together the original page. Again assuming uniformity of paper, layout and font. I venture that a line of text is harder to mach than a column of text. There is a certain balance here. While a line contains more meaningful information, a whole sentence perhaps – it also has fewer markers, fragments of words, that would match it to the strips of paper on either side of it. You gain information in one way and lose it in another. Specifically the anchoring within the larger body.

But the analogy we’re pursuing here is application functionality as reading a complete text: whole book to page to line.

Alright, so we have a large pile of individual strips of paper. Now, how do we read the book?

The premise being that the application, the book in out analogy, is concealed among a large body of code. Where only those knowing exactly what to look for, can find it. The secret in steganography is not the decryption key but how to find what you are looking for – the detection key if you will.
A steganographic application would have to have a detection key. With which you can locate the application and without which you can not. A link to first page, in the book analogy.

In a book you can just turn the pages but here all the pages are separated from one another. How do you get from page to page – or from one line to the next, in the more fine grained analogy.

Each page has a link to the next page but that link is only usable to someone who has a key. Else anyone stumbling on a page would discover the whole book. The idea was that a page does not guarantee a book. Given a pile of pages you can’t know how many books are in it or even if there are any at all. All you have are disjointed pages. Or code.