-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
tls: fix object prototype type confusion #14447
Conversation
@@ -231,7 +231,7 @@ exports.checkServerIdentity = function checkServerIdentity(host, cert) { | |||
// Example: | |||
// C=US\nST=CA\nL=SF\nO=Joyent\nOU=Node.js\nCN=ca1\[email protected] | |||
exports.parseCertString = function parseCertString(s) { | |||
var out = {}; | |||
var out = Object.create(null); |
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 have treated other changes like this as semver-major. Think this will cause breakage?
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 might, hard to say. It would break conn.getPeerCertificate().hasOwnProperty(k)
but then again, such code is vulnerable to object manipulation now.
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.
Yes, but it's still technically semver-major. @nodejs/ctc ... thoughts?
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 think it should be semver-major, as currently parseCertString
is documented. I would prefer otherwise.
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 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.
Then it's not semver-major for me. I'd go for semver-minor, or even patch.
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 are too many PRs interacting with this change.
return; | ||
|
||
if (c.infoAccess.hasOwnProperty(key)) | ||
if (key in c.infoAccess) |
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.
Perhaps a c.infoAccess[key] === undefined
would be more efficient?
Or just save the value to a variable and use that value here and use it to skip the lookups below.
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.
Unlikely to matter because it's only a handful of keys (if it's set at all.) This is shorter so that's what I picked.
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.
Did a micro benchmark for that on TF&I. Small benefit for in
> var o = {a:1, b:2, c:3, d:4, e:5}
> var j = 0
> console.time('in'); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (key in o) ++j};console.timeEnd('in')
in: 2614.723ms
> console.time('!=='); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (o[key] !== undefined) ++j};console.timeEnd('!==')
!==: 3160.657ms
> console.time('!in'); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (!(key in o)) ++j};console.timeEnd('!in')
!in: 2842.438ms
> console.time('==='); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (o[key] === undefined) ++j};console.timeEnd('===')
===: 2884.768ms
> console.time('!=='); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (o[key] !== undefined) ++j};console.timeEnd('!==')
!==: 2999.367ms
> console.time('==='); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (o[key] === undefined) ++j};console.timeEnd('===')
===: 3113.552ms
> console.time('!in'); for (let i = 0; i < 1e8; ++i) {const key = String.fromCharCode(97 + (i % 10)); if (!(key in o)) ++j};console.timeEnd('!in')
!in: 2679.466ms
>
lib/_tls_common.js
Outdated
@@ -169,21 +169,18 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) { | |||
if (!c) | |||
return null; | |||
|
|||
if (c.issuer) c.issuer = tls.parseCertString(c.issuer); | |||
if (c.issuerCertificate && c.issuerCertificate !== c) { | |||
if (c.issuer != null) c.issuer = tls.parseCertString(c.issuer); |
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.
Can't we just do a strict comparison against undefined
? parseCertString()
shouldn't be returning null
?
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 not sure I understand your question. The idea is to call parseCertString() for empty strings but not null or undefined.
Rebased now that #14473 landed. New CI: https://ci.nodejs.org/job/node-test-pull-request/9374/ |
This needs to be rebased again, sorry. |
So maybe we do need 12981 lib: save a reference to intrinsic constructs |
@refack Elaborate? I don't understand what that PR has to do with this PR. |
If we are worried about "prototype injection" we could save a pristine sealed copy of |
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.
LGTM
Use `Object.create(null)` for dictionary objects so that keys from certificate strings or the authorityInfoAccess field cannot conflict with Object.prototype properties.
Aha, like that. That's actually quite clever but since this is semver-major anyway, I think I'll go for the most obvious approach for now. Maybe we can use it in a back-port to the stable branches. |
Rebased + new CI: https://ci.nodejs.org/job/node-test-pull-request/9709/ |
Landed in 0f7c06e |
Use `Object.create(null)` for dictionary objects so that keys from certificate strings or the authorityInfoAccess field cannot conflict with Object.prototype properties. PR-URL: #14447 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Fedor Indutny <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
Use `Object.create(null)` for dictionary objects so that keys from certificate strings or the authorityInfoAccess field cannot conflict with Object.prototype properties. PR-URL: nodejs#14447 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Fedor Indutny <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
Use `Object.create(null)` for dictionary objects so that keys from certificate strings or the authorityInfoAccess field cannot conflict with Object.prototype properties. PR-URL: nodejs/node#14447 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Fedor Indutny <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Sakthipriyan Vairamani <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
Fix for #11771. Note that the other two are fixes for (arguably minor) security vulnerabilities.
I don't think core is directly affected but user applications might be susceptible to type confusion stemming from manipulating
__proto__
or properties inherited fromObject.prototype
.CI: https://ci.nodejs.org/job/node-test-pull-request/9320/