12/28/2021

[Bug] Google Cloud Run decodes url search part before reaching your app

Today I discovered a (insane đŸ€Ż) bug in Google Cloud Run.

I was trying to understand WHY đŸ˜”‍đŸ’« Image-Charts works on Google Kubernetes Engine (GKE) but the same container does not work on Cloud-Run.

To be precise, why the signed URL (HMAC) below works on GKE and not on Cloud-Run

https://image-charts.com/chart?chbr=8&chd=t%3A10%2C15%2C25%2C30%2C40%2C80&chf=b0%2Clg%2C90%2C05B142%2C1%2C0CE858%2C0.2&chl=%7C%7C%7C%7C%2033%25%20%21%7Cx2%20&chma=0%2C0%2C10%2C10&chs=700x450&cht=bvs&chtt=Revenue%20per%20month&chxl=0%3A%7CJan%7CFev%7CMar%7CAvr%7CMay&chxs=1N%2AcUSD0sz%2A%2C000000%2C14&chxt=x%2Cy&icac=fgribreau&ichm=d92a75886c0657013da32eda4d82b8db3af39d355b3419caebd5952bc827990d

Note that HMAC signature (ichm query parameter) is computed like this:

ichm=sign(url.search, shared_secret)

My main intuition was that cloud-run had some internal reverse proxies that changes part of the URL on the fly.

If that's trye, let's find what encoded characters Cloud-Run would automatically decode in the URL query part before reaching your app:

new Array(155).join('-').split('-').map((x, i) => '%'+i.toString(16).toUpperCase()).join('-_-')

// output:
// %0-_-%1-_-%2-_-%3-_-%4-_-%5-_-%6-_-%7-_-%8-_-%9-_-%A-_-%B-_-%C-_-%D-_-%E-_-%F-_-%10-_-%11-_-%12-_-%13-_-%14-_-%15-_-%16-_-%17-_-%18-_-%19-_-%1A-_-%1B-_-%1C-_-%1D-_-%1E-_-%1F-_-%20-_-%21-_-%22-_-%23-_-%24-_-%25-_-%26-_-%27-_-%28-_-%29-_-%2A-_-%2B-_-%2C-_-%2D-_-%2E-_-%2F-_-%30-_-%31-_-%32-_-%33-_-%34-_-%35-_-%36-_-%37-_-%38-_-%39-_-%3A-_-%3B-_-%3C-_-%3D-_-%3E-_-%3F-_-%40-_-%41-_-%42-_-%43-_-%44-_-%45-_-%46-_-%47-_-%48-_-%49-_-%4A-_-%4B-_-%4C-_-%4D-_-%4E-_-%4F-_-%50-_-%51-_-%52-_-%53-_-%54-_-%55-_-%56-_-%57-_-%58-_-%59-_-%5A-_-%5B-_-%5C-_-%5D-_-%5E-_-%5F-_-%60-_-%61-_-%62-_-%63-_-%64-_-%65-_-%66-_-%67-_-%68-_-%69-_-%6A-_-%6B-_-%6C-_-%6D-_-%6E-_-%6F-_-%70-_-%71-_-%72-_-%73-_-%74-_-%75-_-%76-_-%77-_-%78-_-%79-_-%7A-_-%7B-_-%7C-_-%7D-_-%7E-_-%7F-_-%80-_-%81-_-%82-_-%83-_-%84-_-%85-_-%86-_-%87-_-%88-_-%89-_-%8A-_-%8B-_-%8C-_-%8D-_-%8E-_-%8F-_-%90-_-%91-_-%92-_-%93-_-%94-_-%95-_-%96-_-%97-_-%98-_-%99-_-%9A

To run this experiment I've set a special route on Image-Charts that outputs what Image-Charts http server got as part of url.search.

On Google Kubernetes Engine (GKE), Image Charts API got an unmodified query string:

%0-_-%1-_-%2-_-%3-_-%4-_-%5-_-%6-_-%7-_-%8-_-%9-_-%A-_-%B-_-%C-_-%D-_-%E-_-%F-_-%10-_-%11-_-%12-_-
%13-_-%14-_-%15-_-%16-_-%17-_-%18-_-%19-_-%1A-_-%1B-_-%1C-_-%1D-_-%1E-_-%1F-_-%20-_-%21-_-%22-_-
%23-_-%24-_-%25-_-%26-_-%27-_-%28-_-%29-_-%2A-_-%2B-_-%2C-_-%2D-_-%2E-_-%2F-_-%30-_-%31-_-%32-_-
%33-_-%34-_-%35-_-%36-_-%37-_-%38-_-%39-_-%3A-_-%3B-_-%3C-_-%3D-_-%3E-_-%3F-_-%40-_-%41-_-%42-_-
%43-_-%44-_-%45-_-%46-_-%47-_-%48-_-%49-_-%4A-_-%4B-_-%4C-_-%4D-_-%4E-_-%4F-_-%50-_-%51-_-%52-_-
%53-_-%54-_-%55-_-%56-_-%57-_-%58-_-%59-_-%5A-_-%5B-_-%5C-_-%5D-_-%5E-_-%5F-_-%60-_-%61-_-%62-_-
%63-_-%64-_-%65-_-%66-_-%67-_-%68-_-%69-_-%6A-_-%6B-_-%6C-_-%6D-_-%6E-_-%6F-_-%70-_-%71-_-%72-_-
%73-_-%74-_-%75-_-%76-_-%77-_-%78-_-%79-_-%7A-_-%7B-_-%7C-_-%7D-_-%7E-_-%7F-_-%80-_-%81-_-%82-_-
%83-_-%84-_-%85-_-%86-_-%87-_-%88-_-%89-_-%8A-_-%8B-_-%8C-_-%8D-_-%8E-_-%8F-_-%90-_-%91-_-%92-_-
%93-_-%94-_-%95-_-%96-_-%97-_-%98-_-%99-_-%9A

On Google Cloud Run however, things are different:

%0-_-%1-_-%2-_-%3-_-%4-_-%5-_-%6-_-%7-_-%8-_-%9-_-%A-_-%B-_-%C-_-%D-_-%E-_-%F-_-%10-_-%11-_-%12-_-
%13-_-%14-_-%15-_-%16-_-%17-_-%18-_-%19-_-%1A-_-%1B-_-%1C-_-%1D-_-%1E-_-%1F-_-%20-_-!-_-%22-_-
%23-_-%24-_-%25-_-%26-_-%27-_-(-_-)-_-*-_-%2B-_-%2C-_---_-.-_-%2F-_-0-_-1-_-2-_-
3-_-4-_-5-_-6-_-7-_-8-_-9-_-%3A-_-%3B-_-%3C-_-%3D-_-%3E-_-%3F-_-%40-_-A-_-B-_-
C-_-D-_-E-_-F-_-G-_-H-_-I-_-J-_-K-_-L-_-M-_-N-_-O-_-P-_-Q-_-R-_-
S-_-T-_-U-_-V-_-W-_-X-_-Y-_-Z-_-%5B-_-%5C-_-%5D-_-%5E-_-_-_-%60-_-a-_-b-_-
c-_-d-_-e-_-f-_-g-_-h-_-i-_-j-_-k-_-l-_-m-_-n-_-o-_-p-_-q-_-r-_-
s-_-t-_-u-_-v-_-w-_-x-_-y-_-z-_-%7B-_-%7C-_-%7D-_-~-_-%7F-_-%80-_-%81-_-%82-_-
%83-_-%84-_-%85-_-%86-_-%87-_-%88-_-%89-_-%8A-_-%8B-_-%8C-_-%8D-_-%8E-_-%8F-_-%90-_-%91-_-%92-_-
%93-_-%94-_-%95-_-%96-_-%97-_-%98-_-%99-_-%9A

Yep. Characters like ")", "(", "a", "~" were converted on the fly by some Cloud Run internal proxy.

Now lets filter this for better readability:

const search_raw = new Array(155).join('-').split('-').map((x, i) => '%'+i.toString(16).toUpperCase());
const search_processed_by_cloud_run = `%0-_-%1-_-%2-_-%3-_-%4-_-%5-_-%6-_-%7-_-%8-_-%9-_-%A-_-%B-_-%C-_-%D-_-%E-_-%F-_-%10-_-%11-_-%12-_-%13-_-%14-_-%15-_-%16-_-%17-_-%18-_-%19-_-%1A-_-%1B-_-%1C-_-%1D-_-%1E-_-%1F-_-%20-_-!-_-%22-_-%23-_-%24-_-%25-_-%26-_-%27-_-(-_-)-_-*-_-%2B-_-%2C-_---_-.-_-%2F-_-0-_-1-_-2-_-3-_-4-_-5-_-6-_-7-_-8-_-9-_-%3A-_-%3B-_-%3C-_-%3D-_-%3E-_-%3F-_-%40-_-A-_-B-_-C-_-D-_-E-_-F-_-G-_-H-_-I-_-J-_-K-_-L-_-M-_-N-_-O-_-P-_-Q-_-R-_-S-_-T-_-U-_-V-_-W-_-X-_-Y-_-Z-_-%5B-_-%5C-_-%5D-_-%5E-_-_-_-%60-_-a-_-b-_-c-_-d-_-e-_-f-_-g-_-h-_-i-_-j-_-k-_-l-_-m-_-n-_-o-_-p-_-q-_-r-_-s-_-t-_-u-_-v-_-w-_-x-_-y-_-z-_-%7B-_-%7C-_-%7D-_-~-_-%7F-_-%80-_-%81-_-%82-_-%83-_-%84-_-%85-_-%86-_-%87-_-%88-_-%89-_-%8A-_-%8B-_-%8C-_-%8D-_-%8E-_-%8F-_-%90-_-%91-_-%92-_-%93-_-%94-_-%95-_-%96-_-%97-_-%98-_-%99-_-%9A`.split('-_-');

search_raw.reduce((m, encoded, i) => encoded === search_processed_by_cloud_run[i] ? m : m.concat([encoded, search_processed_by_cloud_run[i]].join(' => ')), []).join('\n')
    
// output
%21 => !
%28 => (
%29 => )
%2A => *
%2D => -
%2E => .
%30 => 0
%31 => 1
%32 => 2
%33 => 3
%34 => 4
%35 => 5
%36 => 6
%37 => 7
%38 => 8
%39 => 9
%41 => A
%42 => B
%43 => C
%44 => D
%45 => E
%46 => F
%47 => G
%48 => H
%49 => I
%4A => J
%4B => K
%4C => L
%4D => M
%4E => N
%4F => O
%50 => P
%51 => Q
%52 => R
%53 => S
%54 => T
%55 => U
%56 => V
%57 => W
%58 => X
%59 => Y
%5A => Z
%5F => _
%61 => a
%62 => b
%63 => c
%64 => d
%65 => e
%66 => f
%67 => g
%68 => h
%69 => i
%6A => j
%6B => k
%6C => l
%6D => m
%6E => n
%6F => o
%70 => p
%71 => q
%72 => r
%73 => s
%74 => t
%75 => u
%76 => v
%77 => w
%78 => x
%79 => y
%7A => z
%7E => ~

I reported this bug to Steren (Product Manager at Google Cloud Run) and hopefully it will be fixed soon :)

12/15/2021

[fr] oxmoto.fr — stratĂ©gie e-commerce 1 an plus tard

Cela fait maintenant 1 an (2020) que j'ai rejoins en tant qu'associĂ© Oxmoto afin d'y dĂ©velopper la partie e-commerce de Oxmoto.fr grĂące Ă  un suivi hebdomadaire. 

Fin 2021 nous avons maintenant franchit une Ă©tape importante car le CA rĂ©alisĂ© chaque semaine correspond au CA annuel de 2020. 

C'est le rĂ©sultat d'efforts continus de la part de toute l'Ă©quipe, d'une approche aggressive #lean et d'une excellence d'exĂ©cution Ă  tous les niveaux. 

2022 s'annonce exceptionnel !
6/16/2021

[Fr] Une sombre histoire de vaccin, d'erreur 500 de FSM et de routing

L’infirmiĂšre a une erreur 500 sur AmeliPro lorsqu’elle souhaitait valider ma premiĂšre dose de vaccin đŸ„Č

Bien entendu — comme tout utilisateur — elle fait donc un retour arriĂšre mais l’application ne respectant pas les principes du web : pas d’Ă©tat portĂ© par l’url -> đŸ”„đŸ’„☠️đŸ„Č

Qu’a-t-elle donc fait ?
Recommencer le cheminement Ă  0 đŸ„Č

Chez Cloud-IAM, Hook0 et feu Redsmin et Bringr nous respect(i)ons le principe de « les interfaces graphiques en tant que machines d'Ă©tats finis » qui map chaque Ă©tat sur un routing associĂ©.

Pour faire simple un état (~ un écran) = une route cÎté front.

La *majoritĂ©* des Ă©tats sont donc accessibles via une URL associĂ©e, permettant de nombreux usages internes et externes (partage de lien, bookmarks, retour arriĂšre, debugging, comprĂ©hension globale des parcours utilisateurs, documentation Ă  jour, automatisation etc…)

Envie d'en savoir plus ? J’en parle en dĂ©tail dans mon livre !

2/17/2021

How to setup your own tmate server with docker

tmate is an awesome tool I use to do work/debug session on someone else terminal. Learn more about tmate here. Sadly their default server is not available anymore, at the time of writing this article you have to setup your own tmate server, I could not find a lot of documentation on internet so here we are!

# ssh into your server (e.g. 51.158.172.10)
# install docker
mkdir tmate && cd tmate

# this command will download the create_keys script and create a "keys" folder in the directory
curl -s -q https://raw.githubusercontent.com/tmate-io/tmate-ssh-server/master/create_keys.sh | bash

# don't forget to setup tmate client on the machine you want and configure ~/.tmate.conf with the information outputed by the previous command

# now let's start the server (don't forget to change "sub.my-domain-name.com") with the domain name pointing to your server
# I choose 2223 but any other port will do

docker run -d --name="tmate-server" \
  --cap-add SYS_ADMIN \
  -v  $(pwd)/keys:/keys \
  -e SSH_KEYS_PATH=/keys \
  -p 2223:2223 \
  -e SSH_PORT_LISTEN=2223 \
  -e SSH_HOSTNAME=sub.my-domain-name.com \
  -e USE_PROXY_PROTOCOL=0 \
  tmate/tmate-ssh-server:prod

Now back on your client machines (e.g. personal laptops, or your friend laptop):

# install tmate client (check https://tmate.io/ for instructions)
nano ~/.tmate.conf

# paste what was printed from create_keys.sh

set -g tmate-server-host "IP_OR_DOMAIN_OF_YOUR_SERVER"
set -g tmate-server-port 2223
set -g tmate-server-rsa-fingerprint SHA256:xxxxxxxxxxxxxxxxxx
set -g tmate-server-ed25519-fingerprint SHA256:xxxxxxxxxxxxxxxxxxxxxx

You now are good to go!

1/17/2021

[Fr] La signature numérique de Sylae ? Bonjour Sisyphe, bienvenue en enfer

L'histoire suivante se passe sur le site Sylae, un site du service-public.

Quelques "MINUTES" pour afficher un formulaire de signature numérique ?!.

C'est forcĂ©ment parce que vous ĂȘtes en train de me gĂ©nĂ©rer une clĂ© avec une complexitĂ© de tarĂ©e right ? RIGHT ?

Moi dans ces cas lĂ , j'ai juste pas la patience (aprĂšs 10 secondes d'attente), je check le code-source.

Et comme c'est un service publique, il y a 80% de chance que ça soit un grand moment (Atos, CapGemini, Sopra, ... FTW).

(issTimeout=300)

"Allez, on va dire qu'au bout de 5 minutes, si le formulaire n'est pas chargé, c'est qu'il y a un problÚme".

NON MAIS LES GARS si vous n'étiez pas les services publics, la moitié du web aurait quitté cette page aprÚs 5 secondes !

Le script JS génÚre du mixed content, les mecs doutent de rien. OKLM.

Mais savez pourquoi ils affichent aprÚs 5 MINUTES le message: "Nous vous invitons à vérifier la configuration de votre poste de travail avec les pré-requis" ????????

En fait vous DEVIEZ savoir prĂ©alablement qu'il fallait lire un PDF pour ajouter des EXCEPTIONS Ă  l'exĂ©cution de l'applet Java en HTTP (sisisisisi). 

Les mixed content en fait c'Ă©tait pas un bug, mais une feature. 

Cher utilisateur, corrige le problĂšme CHEZ TOI (pov' naz).

Fun fact: il n'y a pas de lien depuis le message pour vous guider vers "la configuration" optimale du "poste de travail" en question (ça serait trop vous aider bande de fainéant)

Une recherche google m'emmÚne le site d'une communauté de commune qui héberge le PDF DE Sylae.

En conclusion : 

  • on te fait dĂ©-facto poireauter 5 minutes
  • on t'affiche un message pour te dire que t'es qu'une merde (je grossis Ă  peine le trait) 
  • ... qu'il te faut vĂ©rifier la "configuration" de "ton poste de travail"
  • ... qui consiste Ă  mettre en place un bypass sĂ©curitĂ©

Quand on connait les deux grosses sociĂ©tĂ©s qui sont derriĂšre le dĂ©veloppement et l'hĂ©bergement de la majoritĂ© des applications des services publiques en France... 
... et le niveau des dĂ©veloppements lĂ  bas 
... et leurs coût

Merci. Changez rien.

[Bonus] Si vous demandez l'impression manuscrite avec signature, on vous affiche ce message. Les mecs n'ont peur de rien.

[Bonus 2] Je vous explique la blague ou bien ?

[Bonus 3] "deployJava.js" quand mĂȘme Oracle s'y met. La factorisation ? Pour quoi faire ?

AprĂšs 1h30 de bataille. 

  • Brave (good point) ne permettant mĂȘme pas de dĂ©sactiver le mixed-content. Contrairement Ă  Chrome/Firefox.
  • Chrome/Firefox/Brave ne supportant plus Java. 
Je me décide à faire l'impensable :

... sauf que c'Ă©tait trop demander Ă  Microsoft:<+p>

C'est partiiiiiiiiiiiiiiiii... 

[3h plus tard. 3. Heures.] Et 1 VM et le vieux windows de ma femme. Toujours pas.

MAIS NOOOOOOON ! Redirection http => https => homepage

Les plus assidus remarquerons que la redirection depuis https va vers une adresse en ... http
A votre avis, le systĂšme SylaĂ© a: 

  1. enregistré mon mot de passe auto-généré MAIS en enlevant des caractÚres spéciaux SANS RIEN DIRE
  2. truncate mon mot de passe auto-généré de 22 caractÚres SANS RIEN DIRE

Et c'Ă©taiiiiiiit ....... đŸ„đŸ„đŸ„đŸ„ un truncate du mot de passe silencieux Ă  20 caractĂšres

Maintenant retour Ă  la case dĂ©part  😭

On notera le ©2014 en footer.  Mais QUI voudrait vous copier ??

+ 3 heures et 6 minutes

[Bonus je-sais-plus-combien] Le code d'erreur qui intĂšgre l'adresse IP (privĂ©e) du serveur qui a traitĂ© la requĂȘte..

DĂ©but d'une 4Ăšme tentative (+3h31). Si IE9+Win7 est trop rĂ©cent, peut-ĂȘtre que WinXP fera l'affaire

La réponse est non

Fin.

« »
 
 
Made with on a hot august night from an airplane the 19th of March 2017.