[Microsoft Login Connector] Security vulnerability in Microsoft Login Connector

Forge Component
(10)
Published on 10 Oct (6 days ago) by Paul Davies
10 votes
Published on 10 Oct (6 days ago) by Paul Davies

Hi,

When implementing this connector in my companies applications I've noticed a unwanted effect of the way this component works; by passing parameters to the OAuthLogin webscreen, you are exposing your client-secret of your (Azure AD-) app to the client. Since these webrequests are before authentication, your client can be anyone with or without malicious intentions.

In detail the following happens:
From a application's logic flow (in outsystems) you do a navigate to the OAuthLogin webscreen (with filled in screen parameters). This results in a HTTP 302 with redirect to [environment]/MicrosoftLoginConnector/CommonFlow.OAuthLogin.aspx including (including query parameters!) to your client's browser. These calls can be inspected via various http sniffing tools including your browsers developer tools (f12 > network tab). See attached image.


Having your clientid and clientsecret exposed could be a massive breach; for example, I was able to get an Active directory token with my apps permissions via the client credential flow (grant_type = client_credential on the /oauth2/token endpoint).

Are you able to fix this / do you need some help? I think that the most easy solution lies with a server side lookup of the clientsecret in a config tabel based on the client id for example.


Regards, Rob



Hi Andreia Gaspar,

Has this vulnerability been addressed already?
It will be a pity if we start forking this component while the fix seems to be very straightforward. 


Kind regards,

Robin 



Rob Mooijman wrote:

Hi,

When implementing this connector in my companies applications I've noticed a unwanted effect of the way this component works; by passing parameters to the OAuthLogin webscreen, you are exposing your client-secret of your (Azure AD-) app to the client. Since these webrequests are before authentication, your client can be anyone with or without malicious intentions.

In detail the following happens:
From a application's logic flow (in outsystems) you do a navigate to the OAuthLogin webscreen (with filled in screen parameters). This results in a HTTP 302 with redirect to [environment]/MicrosoftLoginConnector/CommonFlow.OAuthLogin.aspx including (including query parameters!) to your client's browser. These calls can be inspected via various http sniffing tools including your browsers developer tools (f12 > network tab). See attached image.


Having your clientid and clientsecret exposed could be a massive breach; for example, I was able to get an Active directory token with my apps permissions via the client credential flow (grant_type = client_credential on the /oauth2/token endpoint).

Are you able to fix this / do you need some help? I think that the most easy solution lies with a server side lookup of the clientsecret in a config tabel based on the client id for example.


Regards, Rob



Hi Rob,


I now have access to publish this component so would be great to get you on the team to work on this fix if you still have time.

Thanks


Paul


Paul Davies wrote:

Rob Mooijman wrote:

Hi,

When implementing this connector in my companies applications I've noticed a unwanted effect of the way this component works; by passing parameters to the OAuthLogin webscreen, you are exposing your client-secret of your (Azure AD-) app to the client. Since these webrequests are before authentication, your client can be anyone with or without malicious intentions.

In detail the following happens:
From a application's logic flow (in outsystems) you do a navigate to the OAuthLogin webscreen (with filled in screen parameters). This results in a HTTP 302 with redirect to [environment]/MicrosoftLoginConnector/CommonFlow.OAuthLogin.aspx including (including query parameters!) to your client's browser. These calls can be inspected via various http sniffing tools including your browsers developer tools (f12 > network tab). See attached image.


Having your clientid and clientsecret exposed could be a massive breach; for example, I was able to get an Active directory token with my apps permissions via the client credential flow (grant_type = client_credential on the /oauth2/token endpoint).

Are you able to fix this / do you need some help? I think that the most easy solution lies with a server side lookup of the clientsecret in a config tabel based on the client id for example.


Regards, Rob



Hi Rob,


I now have access to publish this component so would be great to get you on the team to work on this fix if you still have time.

Thanks


Paul


Good job! Sure, I'll send you a DM.


Hi,

Is there any time schedule in which we can expect a fix for this, or should i better not wait and make the fix ourselves?

Regards,

Daniel

Daniël Kuhlmann wrote:

Hi,

Is there any time schedule in which we can expect a fix for this, or should i better not wait and make the fix ourselves?

Regards,

Daniel

Hi Daniel,


Rob and I had a chat at the end of last year and he was looking to make the update but no firm planned timelines were established.  If you would like to do the update for the community and have time then let's add you to the components team so you make the update and publish.

Thanks

Paul D.

 


Daniël Kuhlmann wrote:

Hi,

Is there any time schedule in which we can expect a fix for this, or should i better not wait and make the fix ourselves?

Regards,

Daniel

Hi Daniël,

I haven't had the focus to make an update yet and it's probably an breaking update. I really can't give you an indication on the delivery, but like Paul said; please share if you have something working.

The fix on this component is basically having a table on the database that contains client ID and secret and passing the identifier (like a GUID or the application identifier) in the query parameters. I've used his pattern in earlier projects, but I haven't got access to the implementation anymore.

Regards,

Rob

Hello everyone,


First thing thank you for the feedback and the help. This is what helps improve the components and this community.

I have uploaded a new version of this component that has a block that doesn't expose the client id. 

This block contains a link that makes the request without navigating to a new screen.
To accommodate these changes we had to create a new site property containing the name of the Module (MicrosoftLoginConnector). So if in your projects you have a different name for the module, please change this site property to contain the name of the connector Module.


The old block is available on the component still so there aren't breaking changes (although it has been deprecated).


Thanks guys ! 

Miguel Amado


Very nice Miguel and thank you very much.

Great team work guys. Thank you all for your efforts. 

Miguel,

I notice that you have uploaded this to OS 10. Will you be updating the OS 11 version?

Paul Davies wrote:

Miguel,

I notice that you have uploaded this to OS 10. Will you be updating the OS 11 version?

Hello Paul,


My mistake. I uploaded a O11 version but labeled it a 010 version.
Already upload the right version.


Cheers 


Miguel Amado wrote:

Paul Davies wrote:

Miguel,

I notice that you have uploaded this to OS 10. Will you be updating the OS 11 version?

Hello Paul,


My mistake. I uploaded a O11 version but labeled it a 010 version.
Already upload the right version.


Cheers 


cool


Hello,

I was wondering if someone already was able to get the latest version (with the WB button) working?

I keep getting the following error message:

AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.
Trace ID: 35897c4a-dc3b-46ed-a928-f1a299ab5300
Correlation ID: a9cc17ac-b9b3-4656-a2f4-0a1e2731311d
Timestamp: 2019-01-25 16:10:54Z

But I am 100% sure using the client secret key that I created that I defined in the Azure Portal under the application keys.

Regards,

Daniel

Hi Daniel,

Did you url encode the secret? On Microsoft side there will be a URL decode, and some non encoded characters will be decoded to other characters. 

To check: get your raw request where you did not apply encoding and try to decode the values. They probably are not the same before and after.


Regards, Rob

Hi Rob,

I just just the component and stored the secret code generated on the Azure Poratal in the site property of the espace.

I will dig deeper into it and see if I can confirm your assumption.

Regards,

Daniel

Daniël Kuhlmann wrote:

Hi Rob,

I just just the component and stored the secret code generated on the Azure Poratal in the site property of the espace.

I will dig deeper into it and see if I can confirm your assumption.

Regards,

Daniel

Hello Daniel,

I believe that Daniel might be right. I've published a new version that is encoding the URL. So if your secret has something like a "+" symbol, previously that could trigger the error that you received. Now, it's encoded on the component , so if that was your problem, it might be fixed in this new version.


Regards,

Miguel Amado


Hi  Miguel,

Thanks, for the quick response and fix. 

It works now as I would expect.

Regards,

Daniel

ps. one final suggestion the demo app still is implemented using the deprecated external URL, if changed it myself to the button webblock. Maybe a good Idea to change this too in the Forge version so others will not have to do that change them self in order to test out the component.

Hi Miguel,

I don't understand how the solution with the web block is supposed to be used.  Who should click the link in the web block? The user? Automatically, using some javascript?
It seems to me like a 'hackish' solution to the problem.  But I'm an Outsystems newbie, so I could be missing something.

I think I fixed this problem in what I believe is a more 'elegant' way.

The original security problem was that a redirect was made to "CommonFlow/OAuthLogin", and that leaked the ClientSecret.

The way I see it, what we want is to run the preparation of the "CommonFlow/OAuthLogin" screen, but without doing the redirect (because that leaks the secret).

Why not put all logic of the "CommonFlow/OAuthLogin" Preparation in a Server Action (except for the redirect to externalUrl). And then do the redirect to Common\ExternalUrl yourself.

The following is an image of the Preparation of the NoPermission screen using this new approach: 

You can see that at the end we call the "OAuth2_Create_AuthorizationRequest" Server Action and do the redirect to the generated url ourselves, instead of redirecting to the 'CommonFlow/OAuthLogin' screen.

So that's two steps instead of one.  But I can live with that.  

Any other code in the 'CommonFlow/OAuthLogin' preparation was moved to the "OAuth2_Create_AuthorizationRequest" Server Action, or removed, because unnecessary.


What do you think about this solution?

Don't hesitate to contact me if you want to discuss this.

Regards,

Steven


Steven Decock wrote:

Hi Miguel,

I don't understand how the solution with the web block is supposed to be used.  Who should click the link in the web block? The user? Automatically, using some javascript?
It seems to me like a 'hackish' solution to the problem.  But I'm an Outsystems newbie, so I could be missing something.

I think I fixed this problem in what I believe is a more 'elegant' way.

The original security problem was that a redirect was made to "CommonFlow/OAuthLogin", and that leaked the ClientSecret.

The way I see it, what we want is to run the preparation of the "CommonFlow/OAuthLogin" screen, but without doing the redirect (because that leaks the secret).

Why not put all logic of the "CommonFlow/OAuthLogin" Preparation in a Server Action (except for the redirect to externalUrl). And then do the redirect to Common\ExternalUrl yourself.

The following is an image of the Preparation of the NoPermission screen using this new approach: 

You can see that at the end we call the "OAuth2_Create_AuthorizationRequest" Server Action and do the redirect to the generated url ourselves, instead of redirecting to the 'CommonFlow/OAuthLogin' screen.

So that's two steps instead of one.  But I can live with that.  

Any other code in the 'CommonFlow/OAuthLogin' preparation was moved to the "OAuth2_Create_AuthorizationRequest" Server Action, or removed, because unnecessary.


What do you think about this solution?

Don't hesitate to contact me if you want to discuss this.

Regards,

Steven


Hello Steven,


The web block is to be clicked by the User on a login page. It's supposed to be customized via css and It's supposed to be easy to use. It's a replace for your login button of your application.

That being said I like your approach ! It gives the developers a wither range of implementing the Microsoft login. Although there is one extra step I think it can be explained  on the component and shown on the example. In future releases I would like to add to the component.

Thanks for sharing. 


Cheers,

Miguel Amado