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

[Security Solution][Detections] Fixes 'Detection Rule "reference url" links don't work if they are created with missing "http://' #112452

Merged
merged 11 commits into from
Sep 30, 2021

Conversation

MadameSheema
Copy link
Member

@MadameSheema MadameSheema commented Sep 16, 2021

Summary

In this PR we are fixing the following issue: #99742

In order to fix it, what we are doing is to don't accept URL's that does not contain the http:// https:// prefix, updating the regex used for the URL validation.

Screenshot 2021-09-20 at 10 23 36

@MadameSheema
Copy link
Member Author

@elasticmachine merge upstream

@MadameSheema MadameSheema changed the title updates url validation to don't accept urls without http or https prefix [Security Solution][Detections] Fixes 'Detection Rule "reference url" links don't work if they are created with missing "http://' Sep 20, 2021
@MadameSheema MadameSheema self-assigned this Sep 20, 2021
@MadameSheema MadameSheema added v7.16.0 release_note:skip Skip the PR/issue when compiling release notes Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Team:Detections and Resp Security Detection Response Team v8.0.0 labels Sep 20, 2021
@MadameSheema MadameSheema marked this pull request as ready for review September 20, 2021 08:26
@MadameSheema MadameSheema requested a review from a team as a code owner September 20, 2021 08:26
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detections-response (Team:Detections and Resp)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

Copy link
Contributor

@ecezalp ecezalp left a comment

Choose a reason for hiding this comment

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

LGTM

@banderror
Copy link
Contributor

LGTM 👍

Just wondering, could we make the validation message more descriptive? E.g. something like

The URLs entered must be valid and start with http:// or https://

@MadameSheema
Copy link
Member Author

Just wondering, could we make the validation message more descriptive? E.g. something like

The URLs entered must be valid and start with http:// or https://

@banderror I think is a great idea, @peluja1012 @rylnd what do you think?

@@ -13,6 +13,10 @@ describe('helpers', () => {
expect(isUrlInvalid('this is not a url')).toBeTruthy();
});

test('verifies as invalid url without http(s):// prefix', () => {
expect(isUrlInvalid('www.thisIsNotValid.com')).toBeTruthy();
});
Copy link
Contributor

@FrankHassanabad FrankHassanabad Sep 20, 2021

Choose a reason for hiding this comment

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

The existing regex you are modifying is not very robust and misses a lot of common use cases.

Examples of tests that it will fail when it should pass would be:

    test('should verify valid wwww such as 4 of them.', () => {
      expect(isUrlInvalid('https://wwww.example.com')).toBeFalsy();
    });

    test('should validate characters such as %22 being part of a correct URL.', () => {
      expect(isUrlInvalid('https://www.exam%22ple.com')).toBeFalsy();
    });

    test('should validate characters incorrectly such as ;', () => {
      expect(isUrlInvalid('https://www.example.com[')).toBeTruthy();
    });

I think also this should include at least one test case for http such as:

    test('verifies valid http url', () => {
      expect(isUrlInvalid('http://www.example.com/')).toBeFalsy();
    });

I always look for what is missing first before moving forward.

If you look online you will see a lot of ambiguous language around the RFC for what are valid and not valid URI characters.
https://datatracker.ietf.org/doc/html/rfc3986
https://stackoverflow.com/questions/1547899/which-characters-make-a-url-invalid

But those I think are common use cases. The encoded characters such as %22 are very common in URL copying and pasting. I think a better way would be to swap the code to use new URL such as this something like this below:

const allowedSchemes = ['http:', 'https:'];

export const isUrlInvalid = (url: string | null | undefined) => {
  try {
    if (url != null) {
      const urlParsed = new URL(url);
      if (allowedSchemes.includes(urlParsed.protocol)) {
        return false;
      }
    }
  } catch (error) {
    // intentionally left empty
  }
  return true;
};

Although this name is isUrlInvalid most developers prefer the positive case such as isUrlValid rather than the negative case fwiw as well if you want to refactor towards that.

Copy link
Contributor

@FrankHassanabad FrankHassanabad Sep 21, 2021

Choose a reason for hiding this comment

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

One more test case that would be helpful reading the code below is to check to ensure empty strings return false since there was an original isEmpty(url) and we want to ensure that the wanted behaviors are the same before any refactoring. So this test would be helpful to add to preserve the original behavior first before the refactoring.

    test('verifies as valid when given an empty string', () => {
      expect(isUrlInvalid('')).toBeFalsy();
    });

Now if you look at my re-factored code above I am introducing an accidental bug and behavioral change because I am not checking this empty string condition so it is a bug. So in reality my code should be more something like this:

const allowedSchemes = ['http:', 'https:'];

export const isUrlInvalid = (url: string | null | undefined) => {
  try {
    if (url != null) {
      if (url === '') {
        return false;
      } else {
        const urlParsed = new URL(url);
        if (allowedSchemes.includes(urlParsed.protocol)) {
          return false;
        }
      }
    }
  } catch (error) {
    // intentionally left empty
  }
  return true;
};

It's a bit more noisy but it adheres to the original behavior which looks to involve allowing a completely empty string to work which I think the original author wanted.

One more test that would be helpful is to double check our understanding of "what about empty spaces"? If the original code did not allow empty spaces, then we should add that test case as well for ourselves and for other programmers refactoring later on such as:

    test('empty spaces should valid as not valid ', () => {
      expect(isUrlInvalid(' ')).toBeTruthy();
    });

A lot of times as I change and refactor code I keep the "old code" commented out and then write the tests to ensure each behavior until I remove the older code for the newer refactored version. I like to swap between them as I encounter more of these types of things to broaden my understanding.

As noted below and to the left it's no mistake I made most of my tests use example.com as that is the recommended URL for testing:
https://datatracker.ietf.org/doc/html/rfc2606#page-2

Lastly, I think JSDocs and looking for examples of them within kibana-core would be helpful to add to the function, including what is looking like a "gotcha" around how empty strings validate as valid URL's.

});

test('empty spaces should valid as not valid ', () => {
expect(isUrlInvalid(' ')).toBeTruthy();
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

if (!isEmpty(url) && url != null && url.match(urlExpression) == null) {
return true;
try {
if (url != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: You could maybe combine these as if (url != null || url === '') { if you want. Most people do, but this is still fine as is to me as this overall PR improves things.

Copy link
Contributor

@FrankHassanabad FrankHassanabad left a comment

Choose a reason for hiding this comment

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

I left a few more comments, but I would resolve things you have taken as feedback if you could. Anything left not addressed people typically see it as the nits weren't resolved but we all fine with leaving nits.

PR's shouldn't go on too long but not too short either in a way.

…s/index.test.ts

Co-authored-by: Frank Hassanabad <frankhassanabad@gmail.com>
@MadameSheema
Copy link
Member Author

@elasticmachine merge upstream

@MadameSheema MadameSheema added the auto-backport Deprecated - use backport:version if exact versions are needed label Sep 29, 2021
@MadameSheema MadameSheema enabled auto-merge (squash) September 29, 2021 18:58
@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 4.3MB 4.3MB -143.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @MadameSheema

@MadameSheema MadameSheema merged commit a33ae63 into elastic:master Sep 30, 2021
kibanamachine added a commit to kibanamachine/kibana that referenced this pull request Sep 30, 2021
… links don't work if they are created with missing "http://' (elastic#112452)

* updates url validation to don't accept urls without http or https prefix

* fixes typo

* fixes linter issue

* refactors to follow recommendations

* Update x-pack/plugins/security_solution/public/common/utils/validators/index.test.ts

Co-authored-by: Frank Hassanabad <frankhassanabad@gmail.com>

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Frank Hassanabad <frankhassanabad@gmail.com>
@kibanamachine
Copy link
Contributor

💚 Backport successful

Status Branch Result
7.x

This backport PR will be merged automatically after passing CI.

kibanamachine added a commit that referenced this pull request Sep 30, 2021
… links don't work if they are created with missing "http://' (#112452) (#113509)

* updates url validation to don't accept urls without http or https prefix

* fixes typo

* fixes linter issue

* refactors to follow recommendations

* Update x-pack/plugins/security_solution/public/common/utils/validators/index.test.ts

Co-authored-by: Frank Hassanabad <frankhassanabad@gmail.com>

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Frank Hassanabad <frankhassanabad@gmail.com>

Co-authored-by: Gloria Hornero <snootchie.boochies@gmail.com>
Co-authored-by: Frank Hassanabad <frankhassanabad@gmail.com>
@MadameSheema MadameSheema deleted the 99742-fix branch October 6, 2021 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed release_note:skip Skip the PR/issue when compiling release notes Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v7.16.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants