-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Block Bindings: Don't show protected fields that are bound to blocks and post meta #6197
Conversation
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN:
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Co-authored-by: Pascal Birchler <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks good, as discussed in the original PR in the Gutenberg repository. The approach taken might be to defensive, but we prefer to stay on the safe side and open it later if that makes more sense rather than take any risk something goes wrong.
As a follow-up during the RC phase, we should figure out how to cover the meta source with unit tests that prevent future regressions. |
I would appreciate unit tests as part of this change |
I saw the comment on Trac and I agree with the reasoning. We will work on tests as soon as possible. |
Adding tests totally makes sense to me. Thanks for pointing that out. I've added some tests for the post meta source, covering the protected values, in this commit. I will take a deeper look tomorrow. Let me know any feedback 🙂 |
We also need to cover the following cases:
|
I wasn't sure how to handle these cases. I added two new tests for this using filters. Let me know if that's not correct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd probably good to add other tests that do the following:
- Test for post meta keys that aren't registered (no register_meta call) to make sure any random post meta key is not exposed by default.
- Tests for meta values that might have unsafe HTML, are they sanitised?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of notes for the tests.
I think this is a sensible change.
In this commit, I've refactored the way the post content is updated because it seems not all tests were getting the correct post context. I'd appreciate a new review on this one. I'm really sorry for all the changes, I just realized after trying to add more tests. |
I've added a test for meta keys that aren't registered here. I've added a test to check unsafe HTML here. EDIT: I'll take a look at this. The block bindings API relies on the HTML API, which takes care of sanitizing the unsafe HTML. Let me know if that is what you have in mind. |
/** | ||
* Update the global $post variable. | ||
*/ | ||
private function updateGlobalPost() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't much value in having that code extracted from its method since it's used only once. It would make the code easier to follow if it was inlined.
You could also avoid adding inline comments by making the code structured like that:
global $post;
$post = self::$post;
$post->post_content = $content;
return apply_filters( 'the_content', self::$post->post_content );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The self::$post
variable is useless anyway because the whole class only operates on the global post.
We can just always work on the global post if that is required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried using the global $post variable only for all the tests, but something is not working as I expected.
It seems that the value of the global $post
variable is undefined
(or the value I defined in wpSetUpBeforeClass
) for the FIRST tests. For the following tests, the global $post
variable becomes always null unless I redefine it.
This happens even if I remove all the logic and I just access that variable.
The way I'm solving that is storing the $post object in a private property when the post is initialized: link. And for each test I assign the global variable to that: link.
However, this feels like a workaround. Any idea if that is expected or how it could be solved?
That's only true for HTML attributes, as outlined in #6197 (comment). For inner HTML, there is |
/** | ||
* Update the global $post variable. | ||
*/ | ||
private function updateGlobalPost() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The self::$post
variable is useless anyway because the whole class only operates on the global post.
We can just always work on the global post if that is required.
* Set up for every method. | ||
*/ | ||
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { | ||
self::$post = $factory->post->create_and_get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per my other comment, the static $post
variable is redundant if you make it global anyway.
> > Co-authored-by: Pascal Birchler <[email protected]>
Co-authored-by: Pascal Birchler <[email protected]>
Co-authored-by: Pascal Birchler <[email protected]>
I assumed that if the attributes or the HTML are replaced properly should be covered for all sources in the binding render tests, right? Do you think that having just one test specific for the post meta like this one would be enough or should we replicate all the tests? |
* | ||
* @covers ::register_block_bindings_source | ||
*/ | ||
public function test_source_value_with_unsafe_html_is_sanitized() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also add another test for a Button block where we put something tricky as the link's URL. Example: javascript:alert('Unsafe HTML')
. I'm not sure if that is the best one, but that's definitely how someone could run JS by updating the dynamic source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering what if we should handle that case in the bindings because passing javascript:alert('1')
to the href it is actually valid HTML. We would only be consuming the value stored in the custom field and exposed in the REST API. Not sure if it should be checked in the block bindings API, as part of the meta fields registration, or as part of the button block.
I hope it's enough because block rending covers the same functionality. |
I added a new test for bindings modifying an HTML attribute like the image src. |
Committed in https://core.trac.wordpress.org/changeset/57754 |
As discussed in Gutenberg plugin, this pull request adds two safety checks to ensure block bindings don't leak private post meta:
It seems safer to add these limitations to ensure no unwanted data is leaked. And it can be explored later how to loosen these restrictions.
To do that this pull request:
$meta_keys
through get_registered_meta_keys function to check if the specific key has theshow_in_rest
property enabled.Testing Instructions
Test it doesn't show the protected value when
show_in_rest
is falseshow_in_rest
set to false:Test protected custom field
show_in_rest
true but protect it. It can be done adding a_
at the beginning of the key or using a filter like this one:Trac ticket: https://core.trac.wordpress.org/ticket/60651
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.