Problem/Motivation

The link widget seems to rely purely on native browser side validation for checking the validity of external URLs. When an invalid URL such as "http:" (on Firefox) or "irc:" (on Chromium and Firefox) is used then these malformed URLs are accepted.

Steps to replicate:

  1. Add a link field on the "Article" node type with the option "Allowed link type" set to "External links only".
  2. Create an article, enter "http:" or "irc:" for the URL, and submit the form.
  3. Result: the invalid URL is accepted.

This was originally reported by idimopoulos.

Proposed resolution

There are two proposals
1) Add validation for punycode and magnet links in /core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator
or
2) Use the Symfony Url Validator, #34. This was proposed 6 years ago in #295021: filter_var() with FILTER_VALIDATE_URL accepts malformed URLs and rejects not all valid URLs and 4 years ago in #2691099: Improve external URL validation in many ways

Remaining tasks

Choose a proposed resolution and if the 1) then decide if these changes should be in UrlHelper See #21

User interface changes

API changes

Data model changes

Release notes snippet

CommentFileSizeAuthor
#67 interdiff_64-67.txt1.83 KBpradhumanjain2311
#67 2652236-67.patch10.45 KBpradhumanjain2311
#64 2652236-64.patch10.27 KBgaurav_manerkar
#63 2652236-63.patch10.11 KBgaurav_manerkar
#62 2652236-62.patch7.56 KBgaurav_manerkar
#60 2652236-60.patch10.08 KByivanov
#55 2652236-55.patch10.04 KBquietone
#55 interdiff-54-55.txt4.47 KBquietone
#55 interdiff-44-51.txt5.08 KBquietone
#54 interdiff_51-54.txt1.54 KBMeenakshi_j
#54 2652236-54.patch10.83 KBMeenakshi_j
#51 insufficient_link_va-2652236-51.patch10.8 KBlogickal
#50 insufficient_link_va-2652236-50.patch0 byteslogickal
#48 interdiff-2652236-44-48.txt4.29 KBvakulrai
#48 validation_external_link-2652236-48.patch10.83 KBvakulrai
#47 validation_external_link-2652236-47.patch10.83 KBvakulrai
#44 2652236-44.patch6.83 KBquietone
#44 interdiff-41-44.txt3.18 KBquietone
#43 2652236-41.patch3.37 KBGhost of Drupal Past
#41 2652236-41.patch3.35 KBquietone
#37 2652236-37.patch2.04 KBjibran
#34 validator.txt2.51 KBGhost of Drupal Past
#30 interdiff.2652236.27-30.txt895 bytessuper_romeo
#30 2652236-30.drupal.Insufficient-link-validation-for-external-URLs.patch5.07 KBsuper_romeo
#27 interdiff-24-27.txt966 bytesDinesh18
#27 2652236-27.patch5.04 KBDinesh18
#24 interdiff-2652236-23-24.txt732 bytespguillard
#24 insufficient_link-2652236-24.patch5.03 KBpguillard
#23 insufficient_link-2652236-23.patch4.93 KBpguillard
#18 insufficient_link-2652236-18.patch5.68 KBMac_Weber
#18 interdiff-14-18.txt737 bytesMac_Weber
#14 link-validation-2652236-14.patch5.71 KBMac_Weber
#14 interdiff-12-14.txt1.59 KBMac_Weber
#12 link-validation-2652236-12.patch4.15 KBMac_Weber
#12 interdiff-9-12.txt1.08 KBMac_Weber
#9 link-validation-2652236-9.patch3.91 KBMac_Weber
#6 http_external_link_accepted_success.png160.79 KBkavithad
#6 irc_external_link_accepted_success.png161.42 KBkavithad
#6 Link_field_configuration.png158.13 KBkavithad
#6 Article_contenttype_fields.png162.72 KBkavithad
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pfrenssen created an issue. See original summary.

pfrenssen’s picture

Title: Insufficient link validation for external URLs on Firefox » Insufficient link validation for external URLs
pfrenssen’s picture

Issue summary: View changes
pfrenssen’s picture

Issue summary: View changes
kavithad’s picture

Assigned: Unassigned » kavithad
kavithad’s picture

Followed the steps mentioned in the issue description to reproduce the issue. However the reported issue seems to be working fine in Drupal 8.x.0. Attached the screenshots for reference.

pfrenssen’s picture

Status: Needs review » Active

@kavithad, thanks for testing!

However you seem to have tested with valid URLs like "irc://irc.server.org/channel", not the invalid URLs such as "irc:" that are mentioned in the issue summary.

swentel’s picture

Related to #2573635: Url::fromUri() should accept protocol-relative URLs - although not entirely the same.

Mac_Weber’s picture

Status: Active » Needs review
FileSize
3.91 KB

I added some code for it that also validates Punycode.
While working on it I realize this is a deeper problem in the class UrlHelper, but we better solve it here first because that class will need some deeper changes in order to be a really good validation. For example, maybe taking help from Symfony UrlValidator and other improvements.

Mac_Weber’s picture

I opened a new issue, as this validation maybe needs a bigger rewrite: #2691099: Improve external URL validation in many ways, but we can still apply this patch to fix this bug until the other issue is discussed.

Status: Needs review » Needs work

The last submitted patch, 9: link-validation-2652236-9.patch, failed testing.

Mac_Weber’s picture

Status: Needs work » Needs review
FileSize
1.08 KB
4.15 KB

Magnet links do not work with parse_url($uri, PHP_URL_HOST);, they need to be parsed by parse_url($uri, PHP_URL_QUERY);

dawehner’s picture

Issue tags: +Needs tests

Let's ensure to expand the test coverage.

Mac_Weber’s picture

Status: Needs review » Needs work
FileSize
1.59 KB
5.71 KB

@dawehner I added tests for Punycode (in UTF-8) and for some malformed URLs.
I could not add a malformed URL like irc:// because in this case there is an exception thrown by the file Url.php at line 303:

    $uri_parts = parse_url($uri);
    if ($uri_parts === FALSE) {
      throw new \InvalidArgumentException("The URI '$uri' is malformed.");
    }

I could not manage to make the test understand it is expected this is a malformed URL. So it still needs a test for irc://.

Mac_Weber’s picture

Assigned: kavithad » Unassigned
Status: Needs work » Needs review

in a chat with @dawehner at IRC, if I understand correctly, handling irc:// in these tests at the patch #14 would require changes in that class and this is out of scope of this issue.

Then, marking patch #14 as 'needs review'.

Status: Needs review » Needs work

The last submitted patch, 14: link-validation-2652236-14.patch, failed testing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Mac_Weber’s picture

removed the test that we are not going to implement.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

pmchristensen’s picture

Version: 8.2.x-dev » 8.3.x-dev
Status: Needs review » Reviewed & tested by the community

Looks really good and very nice with a solution for better link validation. I have run the patch against 8.3.x which is the current Drupal 8 Core development and run phpunit test also. Everything is looking really good and therefore I have changed status. Lets get this patch ported right?

$ ../vendor/bin/phpunit --group link -v
PHPUnit 4.8.27 by Sebastian Bergmann and contributors.

Runtime:	PHP 7.0.11-1+deb.sury.org~trusty+1 with Xdebug 2.5.0-dev
Configuration:	/www/drupal8/web/core/phpunit.xml

.

Time: 2.8 minutes, Memory: 132.00Mb

OK (1 test, 33 assertions)
cilefen’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue summary update
  1. +++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
    @@ -39,9 +39,44 @@ public function validate($value, Constraint $constraint) {
    +      // External URLs validation.
    

    The comment seems superfluous because from the following line this is obvious. But maybe some people would like it.

  2. +++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
    @@ -39,9 +39,44 @@ public function validate($value, Constraint $constraint) {
    +          // Converts Punycode to ASCII.
    

    This comment is superfluous.

  3. +++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
    @@ -39,9 +39,44 @@ public function validate($value, Constraint $constraint) {
    +          // Validates the URL.
    

    This comment is pointless. There are other comments that serve no purpose.

  4. +++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
    @@ -39,9 +39,44 @@ public function validate($value, Constraint $constraint) {
    +        // If cannot do Punycode validation, then just checks the presence of
    +        // a hostname;
    

    This sentence doesn't make much sense.

  5. +++ b/core/modules/system/system.install
    @@ -820,6 +820,23 @@ function system_requirements($phase) {
    +    $installation_url = '//secure.php.net/manual/intl.setup.php';
    +    $documentation_url = 'https://secure.php.net/manual/en/book.intl.php';
    

    Why use a relative protocol and https on consecutive lines?

I have read the comments but I am missing the point as to why these changes do not belong in UrlHelper itself. This issue summary needs a rewrite to explain what is actually going on with this patch. And I am wondering if the test coverage covers all paths.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

pguillard’s picture

This patch contains :

  • A reroll to pass on 8.4.x-dev branch
  • Addresses points 1,2,3,4,5
  • Does not address the point about moving that to the UrlHelper class.
pguillard’s picture

Status: Needs work » Needs review
FileSize
5.03 KB
732 bytes

Added 2 tests for common protocol typos like htp:// and http:/

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

chenderson’s picture

Status: Needs review » Needs work

Good work so far, however I am not sure what is trying to be achieved. Yes the patch will return invalid for irc: but you can still get http://invalid accepted. Is that meant to be the case? Feels like the task needs to be a bit clearer.

+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
@@ -24,9 +24,39 @@ public function validate($value, Constraint $constraint) {
+        $is_invalid_protocol =  !in_array($protocol, UrlHelper::getAllowedProtocols());

There is a small issue with double spacing after equals sign.

Also would it not make sense to return the violation if $is_invalid_protocol return true and save doing the additional checks thereafter?

Dinesh18’s picture

Status: Needs work » Needs review
FileSize
5.04 KB
966 bytes

Here is an updated patch and interdiff which implemented as per #26

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

super_romeo’s picture

Error:

Deprecated function: idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated in Drupal\link\Plugin\Validation\Constraint\LinkExternalProtocolsConstraintValidator->validate() (line 50 of core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php).

@see http://php.net/manual/en/function.idn-to-ascii.php

7.2.0 INTL_IDNA_VARIANT_2003 has been deprecated; use INTL_IDNA_VARIANT_UTS46 instead.

Patch fixed.

Status: Needs review » Needs work

The last submitted patch, 30: 2652236-30.drupal.Insufficient-link-validation-for-external-URLs.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Ghost of Drupal Past’s picture

FileSize
2.51 KB

Perhaps using the Symfony Url validator could be useful? I just added it to our codebase , commit attached, it should be quite easy to adjust it for core. Things I had trouble with:

  1. figuring out %value (UrlValidator::validate sets {{ value }} which DrupalTranslator::processParameters translates to %value)
  2. LinkUriValidConstraint needs to extend Url otherwise we get a type error, it's not enough to extend Constraint.
  3. Minor problem but the try-catch is necessary to avoid the errors caught by other validators throwing an exception.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

quietone’s picture

Title: Insufficient link validation for external URLs » Insufficient link validation for external URLs in link widget
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update +Bug Smash Initiative
Related issues: +#3151047: Expand LinkWidget test coverage, +#2474191: UrlHelper::isValid() should handle hyphens, '-', correctly, +#2691099: Improve external URL validation in many ways

Found this issue while working on #3151047: Expand LinkWidget test coverage for the Bug Smash Initiative.

The next steps here is to decide on which of the proposed resolutions to implement. Setting to NR for that discussion.

jibran’s picture

Let's start from #34.

Status: Needs review » Needs work

The last submitted patch, 37: 2652236-37.patch, failed testing. View results

quietone’s picture

Status: Needs work » Needs review

Drupal\Tests\link\Functional\LinkFieldTest::testURLValidation is failing on the test of these internal links

'?example=llama' => '?example=llama',
      '#example' => '#example',,

And I suspect the other tests are failing on $url3 = '#net'; So, it is not playing nicely with internals that don't start with a '/'.

Ghost of Drupal Past’s picture

Oh dear, if you are starting from there, you should use https://gist.github.com/chx/e6cf5783b76e3e9637e9d6b756f99cf6 it's much better.

quietone’s picture

Thanks!

Here is a patch using that constraint.

Status: Needs review » Needs work

The last submitted patch, 41: 2652236-41.patch, failed testing. View results

Ghost of Drupal Past’s picture

FileSize
3.37 KB

Edit: No idea what's going on here, just quickly added a + ['scheme' => ''] to make that error go away. I am not going to work on this, I am afraid.

quietone’s picture

Working on fixing the tests.

Status: Needs review » Needs work

The last submitted patch, 44: 2652236-44.patch, failed testing. View results

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

vakulrai’s picture

Status: Needs work » Needs review
FileSize
10.83 KB

Adding A patch for 9.2.x. Made few changes to the tests.
Please review.

vakulrai’s picture

Fixed Cspell issues in #47 and adding inter diff.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

logickal’s picture

Patch in #48 wasn't applying and had two PHPCS failures. Resolved and re-rolled.

logickal’s picture

Previous patch was bogus, please ignore. Corrected patch attached.

Status: Needs review » Needs work

The last submitted patch, 51: insufficient_link_va-2652236-51.patch, failed testing. View results

Ghost of Drupal Past’s picture

Thanks for your work on this. When $url becomes empty you get a notice, so I'd recommend wrapping if (!$url = $urlObject->setAbsolute()->toString()) { return; } like this. As I said before, Smartsheet runs this in production, so we already hit the bugs :)

Meenakshi_j’s picture

Status: Needs work » Needs review
FileSize
10.83 KB
1.54 KB

Fixed the fails of #51 and wrapped $urlObject->setAbsolute()->toString() the line.

quietone’s picture

Started a review and immediately made a missing interdiff. Looking at it there are out of scope changes as well as changes to a test, which should not be happening. So, I made a new patch.

What I am confused about is that now these two URLs are considered invalid

      ["http://foo.com/unicode_(✪)_in_parens", [$violation_2]],
      ["http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", [$violation_2]],

But the page they came from states they are valid.

Status: Needs review » Needs work

The last submitted patch, 55: 2652236-55.patch, failed testing. View results

Gribnif’s picture

Perhaps there is something unique about my test setup, but even with the latest patch installed I continue to get an exception rather than a nicely formatted error message when processing an internal URI that is missing the leading slash, such as node/1. I suggest adding a test for this.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

yivanov’s picture

Reroll patch for 9.4.x

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

gaurav_manerkar’s picture

FileSize
7.56 KB

Currently multiple error messages are getting displayed when `link text` is enabled.
More information is described in issue https://www.drupal.org/project/drupal/issues/3077149

I have rerolled patch #60 by adding a fix for error message display. Apply this patch along with patch from above issue.

gaurav_manerkar’s picture

FileSize
10.11 KB

Reroll patch for #62

gaurav_manerkar’s picture

FileSize
10.27 KB

Reroll patch for #62

ameymudras’s picture

Status: Needs work » Needs review

@gaurav moving to needs review on your behalf, also triggering tests

ameymudras’s picture

Status: Needs review » Needs work

Did a quick code review and the following issues were observed

Maybe we should wrap this statement as its 167 chars

          $this->context->setNode($this->context->getValue(), $this->context->getObject(), $this->context->getMetadata(), $this->context->getPropertyPath() . '.uri');

The comment is not descriptive and also we could just log the exception message

catch (\Exception $e) {
        // This is not our job, it can be invalid internal path and more.
      }
pradhumanjain2311’s picture

Status: Needs work » Needs review
FileSize
10.45 KB
1.83 KB

Try to address comment #66.
Please review.

Status: Needs review » Needs work

The last submitted patch, 67: 2652236-67.patch, failed testing. View results

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.