Skip to content

Conversation

yoff
Copy link
Contributor

@yoff yoff commented Feb 23, 2021

The world has moved on, so this query is out of date in that its premise (that default constructors are insecure) has been invalidated (by the addition of fluent APIs to change defaults after construction). Therefor the QL help has been updated and the query has been limited to flag problems only when the version is older than the introduction of the fluent API.

Hence, this PR does the following:

  • use API graphs
  • update .qlhelp-file
  • limit to versions below 3.4
  • move tests to its own directory to only test on old version

- use API graphs
- update .qlhelp-file
- limit to versions below 3.4
- move tests to its own directory to only test on old version
Copy link
Contributor

@felicitymay felicitymay left a comment

Choose a reason for hiding this comment

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

Thanks for including a change note and for updating the query help file 😄

I've made a few text suggestions, but wasn't able to see the output of the Qhelp preview check run as this no longer seems to generate an artifact. I've flagged this to the CodeQL core team in case they have any suggestions.

Comment on lines 40 to 46
Note that <code>ssl.wrap_socket</code> has been deprecated in
Python 3.7. A preferred alternative is to use
<code>ssl.SSLContext</code>, which is supported in Python 2.7.9 and
3.2 and later versions.
3.2 and later versions or the convenience function
<code>ssl.create_default_context</code>, which is supported in Python
3.4 and later versions.
</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately, I can't add a suggestion here - GitHub complains about "deleted lines" which seems like a bug (in the tooltip if not in the functionality).

This is getting a little overlong and complex. I'd suggest breaking out into bullets for clarity and readability.

Note that <code>ssl.wrap_socket</code> has been deprecated in
Python 3.7. The recommended alternatives are:</p>
<ul>
  <li><code>ssl.SSLContext</code> - supported in Python 2.7.9,
         3.2, and later versions</li>
  <li><code>ssl.create_default_context</code> - a convenience function,
         is supported in Python 3.4 and later versions.</li>
</ul>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I hope we will be able to see the result of my attempt at adapting this :-)

Copy link
Member

@RasmusWL RasmusWL left a comment

Choose a reason for hiding this comment

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

I had a look at our discussion from last time you looked at this query (#3580). Our conclusion back then was that even though TLS 1.2 can be used in an insecure manner, we should only alert on version < TLS 1.2.

So TLS 1.1 should also be alerted on, and from my reading of https://docs.python.org/3.9/library/ssl.html#ssl.SSLContext, TLSv1.1 and TLSv1 are allowed with the default ssl.SSLContext() call.

However, it seems like newer versions of the API expects bit-fiddling with the options field -- is that maybe what you've referred to as fluent API? and maybe that was the change that happened in Python 3.4? In any circumstance, I would really like you to add a comment to the QL code explaining what happened in Python 3.4 😊

ctx = ssl.SSLContext()
ctx.options |= ssl.OP_NO_TLSv1
ctx.options |= ssl.OP_NO_TLSv1_1

Is the plan that we will handle such cases with the py/insecure-protocol query? and therefore, that this query should only alert on old code that doesn't support this bit-fiddling of the options field? (since clearly, just spotting the context creation with ssl.SSLContext() is not enough information to tell if that context is going to be secure or not)

I think it's all starting to come together for me, but I would have really liked for you to explain this stuff (in comment in the code, so we can see it in the future), instead of me doing detective work to figure it out 😄


It took me a long time to understand that the test-file InsecureProtocol was a direct copy of the old test-file. I added a few comments for cleaning up the test-file, since I thought this was something new you just wrote. I think this might be a great time to clean up the test-file anyway, but now you know why I have been so nit-picky.

Comment on lines 19 to 27
# not relevant
wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3)
wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1)
wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2)

Context(SSL.SSLv3_METHOD)
Context(SSL.TLSv1_METHOD)
Context(SSL.SSLv2_METHOD)
Context(SSL.SSLv23_METHOD)
Copy link
Member

Choose a reason for hiding this comment

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

nitpick:
What are these? If they're just your own verification that API graphs actually work, I don't think they should be in the query, but in some tests of API graphs 😉

Comment on lines 51 to 52
# FP for insecure default
ssl.SSLContext(ssl.SSLv23_METHOD)
Copy link
Member

Choose a reason for hiding this comment

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

To my understanding, with Python 2.7.16 this is the same as using SSLContext(), which is the same as SSLContext(ssl.PROTOCOL_TLS). So I think those cases should by under the # possibly insecure default heading, and it should be explained they actually do the same thing.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, probably the heading should be something else... but grouping things together that does the same thing seems reasonable 😊

@@ -0,0 +1,52 @@
import ssl
from pyOpenSSL import SSL
Copy link
Member

Choose a reason for hiding this comment

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

I don't see any mention of pyOpenSSL in the insecure default protocol... does that means that default values of pyOpenSSL is always safe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, in that SSL.SSLContext requires a protocol argument; there is no default.

yoff and others added 2 commits February 26, 2021 08:53
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
@yoff
Copy link
Contributor Author

yoff commented Feb 26, 2021

I think it's all starting to come together for me, but I would have really liked for you to explain this stuff (in comment in the code, so we can see it in the future), instead of me doing detective work to figure it out 😄

I guess my hope that it would be explained by this comment was a bit naive. I will add a comment at the top of the query explaining that it only makes sense for older version of Python.

@RasmusWL
Copy link
Member

RasmusWL commented Feb 26, 2021

I will add a comment at the top of the query explaining that it only makes sense for older version of Python.

👍 This, and the interplay with py/insecure-protocol should also be highlighted in the qhelp file. Possibly along with an example of how the new Python 3.4+ API allows secure usage of default values (I guess that's a matter of how the qhelp file writing turns out)

yoff and others added 2 commits February 26, 2021 10:56
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
@yoff
Copy link
Contributor Author

yoff commented Feb 26, 2021

I explained the interplay in the .ql-file rather than in the help as it felt more natural. I did add an example of recommended use, though, that felt natural too.

@yoff yoff requested review from RasmusWL and felicitymay February 26, 2021 19:21
@yoff yoff mentioned this pull request Feb 26, 2021
8 tasks
@yoff
Copy link
Contributor Author

yoff commented Mar 1, 2021

@RasmusWL, thanks for digging into this, I have now revised the PR based on your insights. For the record, this is basically that for this query attention should be restricted to the call ssl.wrap_socket, which is the only way to create a socket with a default that cannot subsequently be modified.

Copy link
Member

@RasmusWL RasmusWL left a comment

Choose a reason for hiding this comment

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

I think all the files this PR touches upon (especially the qhelp file, and the example) needs to have all references to SSLContext removed, maybe except for an example of how to use its' wrap_socket method in a safe manner. This query doesn't report on it anymore, so let's keep make our documentation match that as well 😉

Also just FYI, the example you added should have this change

-context.minimum_version(ssl.TLSVersion.TLSv1_2)
+context.minimum_version = ssl.TLSVersion.TLSv1_2

Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
@yoff yoff added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Mar 3, 2021
@yoff
Copy link
Contributor Author

yoff commented Mar 3, 2021

@felicitymay Thank you for your comments, unfortunately much of the material has now been rewritten. I would be grateful for another look :-)

Ah, I just noted the new procedure for requesting this :-)

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2021

Hello @github/docs-content-codeql : this PR is ready for docs review.

Copy link
Member

@RasmusWL RasmusWL left a comment

Choose a reason for hiding this comment

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

This part of the qhelp file still needs to be changed so it doesn't talk about how default params of ssl.SSLContext are bad:

<p>
The following code shows two different ways of setting up a connection
using SSL or TLS. They are both potentially insecure because the
default version is used.
</p>
<sample src="examples/insecure_default_protocol.py" />
<p>
Both of the cases above should be updated to use a secure protocol
instead, for instance by specifying
<code>ssl_version=PROTOCOL_TLSv1_2</code> as a keyword argument.
</p>
<p>
The latter example can also be made secure by modifying the created
context before it is used to create a connection and so will not be
flagged by this query. However, if a connection is created before
the context has been secured (e.g. by setting the value of <code>minimum_version</code>),
then the code should be flagged by the query <code>py/insecure-protocol</code>.
</p>
<p>
Note that <code>ssl.wrap_socket</code> has been deprecated in
Python 3.7. The recommended alternatives are:
</p>
<ul>
<li><code>ssl.SSLContext</code> - supported in Python 2.7.9,
3.2, and later versions</li>
<li><code>ssl.create_default_context</code> - a convenience function,
supported in Python 3.4 and later versions.</li>
</ul>
<p>
Note also that, even using these alternatives, it is recommended to
ensure that a safe protocol is being used. The following code illustrates
how to use either flags (available since Python 3.2) or the `minimum_version`
field (favored since Python 3.7) to restrict the protocols accepted when
creating a connection.
</p>
<sample src="examples/secure_default_protocol.py" />
</example>

☝️ is basically what I tried to say in the non-example part of #5246 (review)

I'm not sure whether any of the references are no longer needed?

@yoff
Copy link
Contributor Author

yoff commented Mar 7, 2021

I think both examples are still valid and I like how this enabled a natural link to py/insecure-protocol after all.

@felicitymay
Copy link
Contributor

felicitymay commented Mar 8, 2021

@adityasharad - somehow this comment: #5246 (comment) wasn't picked up by our workflow. I'm not sure what the problem is but can see that the team name doesn't show up in bold as it would in a normal comment. (Update: Shati pointed out that this might be because the author of the comment is not a member of the github organization.)

Copy link
Contributor

@felicitymay felicitymay left a comment

Choose a reason for hiding this comment

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

A couple of small text suggestions, a question, and a possible bug in the qhelp -> markdown conversion. Otherwise, the text looks generally clear.

Comment on lines 41 to 43
The latter example can also be made secure by modifying the created
context before it is used to create a connection and so will not be
flagged by this query. However, if a connection is created before
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not clear to me from this text whether we mean the second example is never flagged by the query because it might be used in a secure way, or the second example is not flagged by the query if it is used in a secure way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is the first option. This query does not use data flow, so it now only flags cases that are immediately insecure. The other query referred to in the next sentence, py/insecure-protocol, uses data flow to detect if a context is made secure before it is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have attempted a clarification now.

<li><code>ssl.create_default_context</code> - a convenience function,
supported in Python 3.4 and later versions.</li>
</ul>
<p>
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a bug in the markdown generated by the Qhelp test here. Note the missing blank line after the bullet list that means that this paragraph is run into the second bullet. I don't think this is an error in the qhelp file.

Note that `ssl.wrap_socket` has been deprecated in Python 3.7. The recommended alternatives are:

* `ssl.SSLContext` - supported in Python 2.7.9, 3.2, and later versions
* `ssl.create_default_context` - a convenience function, supported in Python 3.4 and later versions.
Note also that, even using these alternatives, it is recommended to ensure that a safe protocol is being used. The following code illustrates how to use either flags (available since Python 3.2) or the \`minimum_version\` field (favored since Python 3.7) to restrict the protocols accepted when creating a connection.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can try inserting a blank line in the help file and see what happens..

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks. That doesn't appear to have made any difference 😞

I'm not sure where we should report this bug in the CodeQL CLI, but it doesn't look as if it should block this PR.

@adityasharad
Copy link
Collaborator

@adityasharad - somehow this comment: #5246 (comment) wasn't picked up by our workflow. I'm not sure what the problem is but can see that the team name doesn't show up in bold as it would in a normal comment. (Update: Shati pointed out that this might be because the author of the comment is not a member of the github organization.)

@felicitymay it was the colon immediately after the team name. Adding a space seems to fix it, will update the workflow.

yoff and others added 6 commits March 9, 2021 13:19
Co-authored-by: Felicity Chapman <felicitymay@github.com>
Co-authored-by: Felicity Chapman <felicitymay@github.com>
Co-authored-by: Felicity Chapman <felicitymay@github.com>
Co-authored-by: Felicity Chapman <felicitymay@github.com>
hopefully this will generate better markdown
@yoff yoff requested a review from felicitymay March 9, 2021 12:30
felicitymay
felicitymay previously approved these changes Mar 9, 2021
Copy link
Contributor

@felicitymay felicitymay left a comment

Choose a reason for hiding this comment

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

Thanks for all the changes. I spotted one more small thing in the text but otherwise it looks okay to me 😄

Co-authored-by: Felicity Chapman <felicitymay@github.com>
tausbn
tausbn previously requested changes Mar 10, 2021
Copy link
Contributor

@tausbn tausbn left a comment

Choose a reason for hiding this comment

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

One minor comment on the query itself, otherwise LGTM.

@yoff yoff requested review from tausbn and RasmusWL March 10, 2021 15:02
@RasmusWL
Copy link
Member

I think both examples are still valid and I like how this enabled a natural link to py/insecure-protocol after all.

Reading over the text and examples again, it does look ok 👍

@RasmusWL RasmusWL removed the request for review from tausbn March 16, 2021 13:10
@RasmusWL
Copy link
Member

🤔 removing the request for review from Taus didn't allow me to merge this PR still 😂

@alexet alexet dismissed tausbn’s stale review March 16, 2021 13:24

Out of date

@RasmusWL RasmusWL merged commit 5097836 into github:main Mar 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Python ready-for-doc-review This PR requires and is ready for review from the GitHub docs team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants