Hi,
I'm Tom.

I'm a software engineer. I live in Shanghai.

Blog  ·  Github  ·  Linkedin
Recent (Full archive →)
  1. Talk: How We Use Istio and OPA for Authorization
  2. Attack Vectors in OAuth 2.0
  3. Exception Handling: Go vs. Java
  4. Microservice health check in Kubernetes
  5. Build a simple protocol over TCP

Site designed by @orourkedesign.

Talk: How We Use Istio and OPA for Authorization

I gave a lightning talk in KubeCon 2019 Shanghai about how we use istio and OPA for authorization.

The video is available on Youtube and the slides can be found here.

 

Attack Vectors in OAuth 2.0

Yesterday I was checking out which OAuth grant type is best fit for mobile applications. It turns out PKCE(Proof Key of Code Exchange) has become the de facto standard.

The issue with implicit grant

The flow for implicit grant is fairly simple.

In step 1, user agent, ie, mobile application, will normally open the browser to redirect resource owner to authorization server. The security implication here is that, using a web-view inside the application may expose resource owner credentials to application.

The attack vectors lie in step 3 after resource owner authorizes the access, the browser will redirect resource owner back to the application. For most mobile platforms, this is done by a special URL pattern, such as “com.foo.bar://callback-url”, applications bind handlers to this URL. So there’s a chance a malicious application also binds a handler to this URL, and gets the token in the URL fragment.

Don’t ignore state parameter

Another attack vector is that, a malicious user places his own access token in the URL fragment. Now the user’s session is replaced with the attacker’s session. The resource the user creates will actually show up in attacker’s account.

Therefore it is crucial for the client application to verify the state parameter after the redirect, to ensure that the session is the one resource owner initiates. The client may generate and store the state in cookie or session before the redirect to authorization server.

This is also the case for authorization code grant without client_secret (which is a trend to replace implicit grant). The attacker may authorize the authorization server with his own credentials, normally the redirect will happen. However the attacker traps the redirect, copy the URL, and send it to the target user, or initialize. A victim may already login, and clicks on the link, now he gets the attacker’s token, and session is replaced.

PKCE to the rescue

The implicit grant and the authorization code grant are both vulnerable if resource owner is redirected to a malicious client. But can we enforce some checks in the authorization server make sure the request comes from a valid client?

PKCE solves this by introducing proof key for code exchange. It is an enhancement on authorization code grant thus the workflow is about the same, except the client needs to

So the idea here is that client sends the challenge in step 1 and prove it has the key to generate the challenge when exchanging for token in step 3. Such that a malicious client is unable to obtain a code without the key, as it is only held by the righteous client.

 

Exception Handling: Go vs. Java

After reading this post Why Go Gets Exceptions Right, I have some thoughts and would like to write down here.

The first thing bumps to my head is why we’re using exceptions in the first place. The answer seems clear, we want to signal the caller of our function that something went wrong.

So how do we do it? In Java we have exceptions, specially checked exceptions with throws keyword in the method signature. Checked means it will be checked by the compiler at the compile time, as a way to inform the caller that certain exceptions are expected to be thrown from the method. While in go, with the ability to return multiple values, go informs the caller by returning an error. It is part of the function signature, the contract between the function and the caller, the caller should receive the result and the error correctly, otherwise the program won’t compile.

Second thing I’m wondering is that does Go really handle exceptions better than Java? Let’s see how Go and Java handle them differently.

If we categorize the exceptions into following categories, language-ignostically(they’re all concepts from Java, but can be interchangable for discussion):

Checked exceptions

As I mentioned above, checked exceptions are enforced for both Java and Go. And for the caller, they should handle the exception properly. Either try-catch in Java, or check if err is not nil in Go. And in go, you can ignore the error by using _, similarly, in Java you can try-catch the exception and does nothing about it.

Runtime exceptions

Runtime exceptions is the exceptions you can’t always detect at the compile time. It could be a null pointer exception, or a index out of bounds exception. In Java, as runtime exception is unchecked, you don’t need to explicitly throws them in the method. In Go, you don’t need to specify an error in the return statement. And for the caller, you have no idea what went wrong, you basically do nothing with it. Or you can explicitly try-catch in Java or defer-recover in Go, otherwise, for Java the exception will bubble up the call stack until some exception handler catches it. And for Go, the panicking will also climb up the stack of the current goroutine until some recover happens. If none of this happens until main method, the program crashes.

Error

Errors are unpreventable and unrecoverable exceptions, like out of memory error. In Java you don’t catch it and In Go you should just let it panic.

So viewing from this angle, the way Go and Java handles exceptions are almost the same. That’s why I don’t think Go is better than Java in this regard. On the contrary, there are things I don’t like about error handling in Go:

 
View the full archive →