Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure manual URL redirection in the frontend #13892

Merged
merged 6 commits into from Sep 25, 2021

Conversation

brianrodri
Copy link
Contributor

Overview

  1. This PR fixes or fixes part of #N/A.
  2. This PR does the following: Verifies that the URLs we redirect to are valid before navigating to them.

Essential Checklist

  • The PR title starts with "Fix #bugnum: ", followed by a short, clear summary of the changes. (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".)
  • The linter/Karma presubmit checks have passed locally on your machine.
  • "Allow edits from maintainers" is checked. (See here for instructions on how to enable it.)
    • This lets reviewers restart your CircleCI tests for you.
  • The PR is made from a branch that's not called "develop".

Proof that changes are correct

No proof of changes needed because this does not change the UX of the app.

PR Pointers

  • Make sure to follow the instructions for making a code change.
  • Oppiabot will notify you when you don't add a PR_CHANGELOG label. If you are unable to do so, please @-mention a code owner (who will be in the Reviewers list), or ask on Gitter.
  • For what code owners will expect, see the Code Owner's wiki page.
  • Make sure your PR follows conventions in the style guide, otherwise this will lead to review delays.
  • Never force push. If you do, your PR will be closed.
  • Oppiabot can assign anyone for review/help if you leave a comment like the following: "{{Question/comment}} @{{reviewer_username}} PTAL"
  • Some of the e2e tests are flaky, and can fail for reasons unrelated to your PR. We are working on fixing this, but in the meantime, if you need to restart the tests, please check the "If your build fails" wiki page.

@oppiabot
Copy link

oppiabot bot commented Sep 21, 2021

Hi @brianrodri please assign the required reviewer(s) for this PR. Thanks!

Copy link
Contributor

@Radesh-kumar Radesh-kumar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@oppiabot
Copy link

oppiabot bot commented Sep 21, 2021

Unassigning @Radesh-kumar since they have already approved the PR.

brianrodri added a commit to brianrodri/oppia that referenced this pull request Sep 21, 2021
@brianrodri brianrodri mentioned this pull request Sep 21, 2021
4 tasks
brianrodri added a commit to brianrodri/oppia that referenced this pull request Sep 21, 2021
@brianrodri brianrodri mentioned this pull request Sep 21, 2021
4 tasks
@brianrodri brianrodri removed the request for review from gp201 September 21, 2021 21:54
brianrodri added a commit to brianrodri/oppia that referenced this pull request Sep 21, 2021
@brianrodri brianrodri mentioned this pull request Sep 21, 2021
4 tasks
Copy link
Member

@seanlip seanlip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM!

Copy link
Member

@gp201 gp201 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@oppiabot
Copy link

oppiabot bot commented Sep 22, 2021

Unassigning @srijanreddy98 since they have already approved the PR.

Copy link

@PauloASilva PauloASilva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSafeReturnUrl() current implementation still allows redirecting to external websites.

@@ -128,6 +128,46 @@ export class UtilsService {
element.offsetHeight < element.scrollHeight);
}
}

// Determines whether the URL is pointing to a page on the Oppia site.
getSafeReturnUrl(urlString: string): string {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSafeReturnUrl('//evil.com') returns //evil.com, what may allow redirect to external websites:

  1. new URL('//evil.com') (line 144) throws exception but validation continues
  2. new URL('//evil.com', document.baseURI); (line 157) succeeds
  3. '//evil.com'.charAt(0) !== '/'(line 163) condition is satisfied

Only relative URLs should be considered safe.
If, redirecting to external websites is a requirement, then known host names should be kept in an AllowList and the urlString checked against that list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, thanks! Redirecting to external websites is not a requirement, so we're fine with only trusting relative paths. Do you know of an API that can detect them securely? Or would checking for a second / suffice?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not an Angular expert but would some of the available Router methods do the job e.g. navigateByUrl()?
I see that Angular Router has a parseUrl() method: it may worth a look at.

If I had to do it in plain JavaScript/TypeScript, probably I would go with something simple (please don't use it as is without further testing):

getSafeReturnUrl(urlString: string): string {
  const anchor = document.createElement('a');
  anchor.href = urlString;

  return (anchor.host === window.location.host)? urlString : '/';
}
Input Output
//evil.com /
https://evil.com /
javascript:alert(1) /
data:,Hello%2C%20World%21 /
/login /login
/ /

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super helpful, thanks Paulo!

I know @srijanreddy98 has been promoting the usage of Angular router. Srijan, do you know of a way to protect against these "fake return URLs" using angular/routers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I've added more test cases and a simple additional check since the approach you provided doesn't protect us from URL-encoded attacks. For now, we're at least a little more secure (I can't find an exhaustive list of test cases, so I'll consider this resolved since our current coverage seems "good enough").

@oppiabot
Copy link

oppiabot bot commented Sep 22, 2021

Hi @brianrodri, it looks like some changes were requested on this pull request by @PauloASilva. PTAL. Thanks!

@seanlip seanlip mentioned this pull request Sep 22, 2021
4 tasks
seanlip pushed a commit that referenced this pull request Sep 23, 2021
* cherry-pickable copy of #13892

* add more test cases and security
@brianrodri brianrodri removed their assignment Sep 23, 2021
@oppiabot oppiabot bot added the PR: don't merge - STALE BUILD The build on this PR is stale and should be restarted. label Sep 25, 2021
@oppiabot
Copy link

oppiabot bot commented Sep 25, 2021

Hi @brianrodri, the build of this PR is stale and this could result in tests failing in develop. Please update this pull request with the latest changes from develop. Thanks!

@oppiabot oppiabot bot removed the PR: don't merge - STALE BUILD The build on this PR is stale and should be restarted. label Sep 25, 2021
Copy link
Member

@vojtechjelinek vojtechjelinek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@brianrodri brianrodri merged commit 8812985 into oppia:develop Sep 25, 2021
34 checks passed
@brianrodri brianrodri deleted the secure-redirection branch September 25, 2021 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants