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

Use HTTPS instead of HTTP #167

Open
svetlyak40wt opened this issue Jun 3, 2018 · 28 comments
Open

Use HTTPS instead of HTTP #167

svetlyak40wt opened this issue Jun 3, 2018 · 28 comments

Comments

@svetlyak40wt
Copy link
Contributor

Hi!

I've noticed that archives are downloaded via http:

CL-USER> (ql:quickload :thread-pool)
To load "thread-pool":
  Load 2 ASDF systems:
    arnesi bordeaux-threads
  Install 1 Quicklisp release:
    thread-pool
Downloading http://beta.quicklisp.org/archive/thread-pool/2012-01-07/thread-pool-20120107-git.tgz
##########################################################################

But I found that they are also available if I change schema to https:

[art@art-osx5:~]% curl -v -s https://beta.quicklisp.org/archive/thread-pool/2012-01-07/thread-pool-20120107-git.tgz > /dev/null
*   Trying 52.85.242.94...
* Connected to beta.quicklisp.org (52.85.242.94) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.quicklisp.org
* Server certificate: Gandi Standard SSL CA 2
* Server certificate: USERTrust RSA Certification Authority
* Server certificate: AddTrust External CA Root
> GET /archive/thread-pool/2012-01-07/thread-pool-20120107-git.tgz HTTP/1.1
> Host: beta.quicklisp.org
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: binary/octet-stream
< Content-Length: 3061
< Connection: keep-alive
< Date: Sun, 03 Jun 2018 19:14:56 GMT
< Last-Modified: Sat, 07 Jan 2012 21:52:07 GMT
< ETag: "9dfcb3dd5692d474d90f7916722d5bf8"
< Accept-Ranges: bytes
< Server: AmazonS3
< Age: 450
< X-Cache: Hit from cloudfront
< Via: 1.1 f9a0ddc3860252ab6c4d02ab024b4891.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: _WSj_KutsQ1kyoFACC3wQs3zq8jbyo5QjQXIcrCb1DJi4mCZKz2CVw==
<
{ [3061 bytes data]
* Connection #0 to host beta.quicklisp.org left intact

It would be great (and more secure) to switch to the HTTPS. What do you think, @xach?

@svetlyak40wt
Copy link
Contributor Author

Here is some system info:

CL-USER> (cl-info:make-cl-info)
OS:   Darwin 15.6.0
Lisp: SBCL 1.4.3
ASDF: 3.3.1.1
QL:  org.borodust.bodge 20180214223017
     quicklisp 2017-10-23
CL-USER> (ql:update-client)
Downloading http://beta.quicklisp.org/client/quicklisp.sexp
##########################################################################
The most up-to-date client, version 2017-03-06, is already installed.
T
CL-USER> (ql:client-version)
"2017-03-06"

@quicklisp
Copy link
Owner

It would be good to do, but there's no straightforward path to do it. Implementations do not all provide HTTPS support, it's not straightforward to make it from scratch or use HTTPS libraries on all supported platforms.

I hope to soon roll out a different form of authentication of downloads via signatures.

@eugeneia
Copy link

Alternatively, for the time being I figure it is possible to point quicklisp at a http proxy that will convert requests to https, I think?

@svetlyak40wt
Copy link
Contributor Author

Is there any news about a new form of authentication for quicklisp?

@Hexstream
Copy link

SHA256 verification of downloads or similar might be easier to implement than HTTPS?...

(Of course, both would be better eventually.)

@mohe2015
Copy link

mohe2015 commented Apr 25, 2019

SHA256 verification of downloads or similar might be easier to implement than HTTPS?...

(Of course, both would be better eventually.)

I don't know if I'm just stupid but I think SHA256 verification doesn't help without HTTPS. I think you need some kind of signature (like pgp) as @quicklisp already suggested

@Hexstream
Copy link

Hexstream commented Apr 25, 2019

You communicate the SHA256 hashes in advance in a secure way authenticated by a signature (as part of the dist metadata download), and then later you download over HTTP (or HTTPS) and verify that the hashes of the files are the expected ones...

@mohe2015
Copy link

mohe2015 commented Apr 25, 2019

@Hexstream So yeah you meant a combination. I thought you meant to only use SHA256 sums.

@svetlyak40wt
Copy link
Contributor Author

By the way, guys, have you seen an alternative package manager https://gitlab.common-lisp.net/clpm/clpm which is able to use a quicklisp distribution and to force HTTPS?

I've found it recently but didn't have time to try.

@ghard
Copy link

ghard commented Mar 13, 2020

I guess integrity is more important than privacy in our case, so the common method would use something like a GPG key to sign the list of package checksums upon distro build. Then, once downloaded and verified, that list can be used to verify individual packages.

That would mean another external dependency and calling inferiors through OS. GPG binaries are readily available on most platforms though.

Otherwise one could depend on ironclad for PK cryptography and signing/verification of the package cksum list. One of GPG's "strengths" is that the distribution signing key could be acquired/verified trough already existing key server infrastructure.

@xach
Copy link
Contributor

xach commented Mar 13, 2020

I have Quicklisp client code for sha256 checking and GPG signature checking in portable CL. See the gpg branch for more info.

Right now the hold up is key management and a bit of infrastructure updates.

@Hexstream
Copy link

I note in passing that Keybase is a pretty great modern alternative to the fairly antiquated GPG infrastructure.

@thephoeron
Copy link

One straightforward approach to handling HTTPS is graceful degradation. You already have HTTP connections with GPG signature checking as the fall-through. Adding platform-specific support is unpleasant, but it's either here or in a dedicated portable SSL library that will have to be bundled into Quicklisp.

From there, make it highly visible when using HTTPS. When not, keep the same interface we're used to.

Is that sufficient or am I overlooking anything?

@Risto-Stevcev
Copy link

Is this still in progress?
I created cl-micropm for some of Quicklisp's limitations (CLPM development seems to have stopped), but it would be nice to have support for HTTPS and Github/Gitlab sources. Or if there's a way to move out Quicklisp's dependency resolution algorithm so that we can build stuff on top of it -- I tried a couple of times to track it down and pull it out in the code but with no success.

@wasamasa
Copy link

wasamasa commented Oct 7, 2022

One alternative to implementing a sufficient amount of GPG in CL is to port OpenBSD's signify instead. It's a lot simpler in comparison and they rely on Ed25519 which is already implemented in CL as part of Ironclad.

@quicklisp
Copy link
Owner

quicklisp commented Oct 11, 2022 via email

@bo-tato
Copy link

bo-tato commented Sep 9, 2023

The pgp branch is from 4 years ago, of course it would be great having proper key policies and signature verification, but in the spirit of not letting perfect be the enemy of good, what about incorporating some changes from https://github.com/rudolfochrist/ql-https in the meantime? It would be:

  1. Shell out to curl for https downloads. curl is now present on almost all unix, mac, and windows boxes, in other words 99% of users. If curl is not available for https download, then download as it's currently doing over http but show a warning
  2. Check file hash and size from release dist for the downloads. This is currently md5sum but if quicklisp dist could be published with sha256sum instead it would be a lot better. Again can just shell out to md5sum or sha256sum and print a warning when it's not available, but on 99% of users it is available. This makes it so if an attacker can get a https cert for quicklisp.org, or temporarily compromise the quicklisp servers and backdoor some releases, they'd have to maintain the compromise for months until users download a new dist containing the hash and size for the attacker's backdoored versions of packages. Of course if these dists are signed with PGP even better.

But in summary just shelling out to curl for https download if it's available, and printing a warning otherwise, would be a simple and immediate and significant improvement in quicklisp security. I think it's quite worthwhile to implement in the meantime as it seems dist signing may be some more years off.

@Risto-Stevcev
Copy link

Shameless plug (again), but I wrote a small, single file package manager for CL (<200 LOC) that reads the Quicklisp sources but prefers git for decentralization, and creates project-local dependencies.

@Lovesan
Copy link

Lovesan commented Sep 29, 2023

The solution may be to include implementation-specific parts of CFFI (cffi-sys package) for minimal FFI, and use WinHTTP on Windows, OpenSSL library on Linux, and similar operating systems(OpenSSL is virtually everywhere, and version 3.0 includes HTTP(S) client, and older versions are out of support anyway), and otherwise default to plain HTTP over sockets(on Mezzano?).

Not sure about the OpenSSL library situation on macOS though, but that OS has something called Core Foundation and its C API includes http-related stuff.

@daninus14
Copy link

Any updates on this?

@bo-tato would you be open to submitting a fork with your suggestion? I think it's a great idea since it takes care of most of the problem.

@quicklisp would you accept a fork?

@quicklisp What do you think about the following:

How many systems are there that don't support https anyway?

I'm sure at this stage it's probably easier to make github/gitlab repositories for those than have to deal with the special cases for the security issues. You don't have to do this though. It should be the responsibility of those systems' maintainers.

It's not so unreasonable to require https in 2024 and only passing a (:allow-non-encrypted-sources T) to be able to download systems that do not provide encrypting. Default should be encrypted and I don't think it's up to quicklisp to have to worry about how to deal with those systems. It's 2024 already...

If you want to be backwards compatible to not upset the community, you could then invert it and have it (:only-encrypted-sources T) instead, though I think that's just simply not up to basic security standards and should really be unnecessary. To the point that if you insist on keeping backwards compatibility it almost makes sense to have a new interface that defaults to encryption and have it be the standard way quicklisp works, and just keep the old way to avoid breaking backwards compatibility. It seems like it's only really one function so you can just name it (ql:load)...

In conclusion, this change should be rather simple and straightforward, with the burden placed on the system maintainers, it can even keep backwards compatibility, and probably 99.9% of users will benefit tremendously.

Any thoughts?

@daninus14
Copy link

@quicklisp Is there any issue bigger than this for quicklisp?

If you are too busy, can you at least comment on what type of implementation are you willing to accept and open it up to the community to submit a pull request for this?

Btw, thanks for all the work on quicklisp in general! 😄

@bo-tato
Copy link

bo-tato commented Jan 12, 2024

@bo-tato would you be open to submitting a fork with your suggestion? I think it's a great idea since it takes care of most of the problem.

https://github.com/rudolfochrist/ql-https is the fork that implements those suggestions (well just checking md5 not sha256 as we can't change the hash format of main quicklisp dist). If quicklisp wants to incorporate those changes I can work on a PR that better merges it into quicklisp proper.

@hpoggie
Copy link

hpoggie commented Apr 29, 2024

I recently noticed Quicklisp was downloading over HTTP. If @quicklisp would accept it I was thinking about making a PR that would merge the changes from ql-https into Quicklisp. I think this is a reasonable solution given that the user probably will have already installed curl, since the instructions at https://www.quicklisp.org/beta/ tell them to.

Alternatively, if there's some way I can help with the pgp branch, I could do that. I'm not too familiar with how that stuff works, but if there's any way I can help with this issue I'd be happy to.

@daninus14
Copy link

I support @bo-tato and @hpoggie with their proposal with the added detail:

We can actually check if curl is available with

(uiop:run-program "curl -V")

So therefore this could be a valid PR where we can check if the above signals some error/condition (wrap it in a handler-case). If it works, then just use curl, if it doesn't then default to the regular HTTP fetch.

Additionally the user could set up some setting*use-https-only* which would fail if curl is not available. This though can be later...

That way this would not break quicklisp for anyone, and at the same time, if curl is available, it would enable by default HTTPS.

I think such a PR would be accepted.

@quicklisp what do you think? This doesn't break anything, and it enables it by default. In the meantime, this is probably the best solution until something better is developed.

@jsirex
Copy link

jsirex commented Nov 19, 2024

I've just read a couple of articles why lisp is not so popular, there no much jobs and projects.

Then, I read a thread 6 years old where people are discussing to make http->https.
I also double checked (> *year* 2007) is T.

@bo-tato
Copy link

bo-tato commented Nov 19, 2024

I've just read a couple of articles why lisp is not so popular, there no much jobs and projects.

Then, I read a thread 6 years old where people are discussing to make http->https. I also double checked (> *year* 2007) is T.

haha it's fair enough that lisp is not popular, there's not much jobs, and ecosystem is quite fractured (or diverse whether you want to call it a word with good or bad connotation). See review of json and testing libraries. I'm not sure if any other language has so many, let alone a language with as few users as common lisp. Also with package management there is many solutions. Some are using ocicl, some qlot, some clpm, some ql-https, some guix, some nix, and some projects like nyxt browser just use git submodules to manage dependencies. There's probably other solutions I haven't heard of and weirder solutions I can't imagine. None of those solutions use insecure http though. I don't think almost anyone doing real development in common lisp now is using quicklisp and http. It is a shame though that most resources for learning common lisp are older so quicklisp is what new users will see recommended, and the maintainer of quicklisp is mostly inactive and seems they won't fix this anytime soon, or even just add a warning to the documentation that quicklisp uses insecure http and recommend some more secure alternatives.

To be fair though, 2007 is a little exaggerated. Maven, the main package management for the most used enterprise language with by far the most dollar resources poured into it's development, was supporting http until 2020, and iirc was connecting over http on default setups as recently as 2015-16, and they say 25% was still connecting over http in 2019...

@jsirex
Copy link

jsirex commented Nov 19, 2024

@bo-tato thanks for providing information. I'm new in lisp and just have found couple of packages like ql-https. But it is anyway quite hard to start.

@tgbugs
Copy link

tgbugs commented Nov 23, 2024

Given the conversation on this issue I wanted to leave an example of
how to bootstrap quicklisp to use https on sbcl that depends only on
git, curl, and openssl (beyond code written in common lisp).

This is a condensed and slightly modified version of my quicklisp https
bootstrap based on work to generate a minimal sbcl docker image.
https://github.com/tgbugs/dockerfiles/blob/master/source.org#sbcl-stripped

The general approach requires three steps

  1. use git to clone from github via https
  2. use @rudolfochrist's ql-https which uses curl internally to retrieve dexador via https
  3. switch to use quicklisp-https-always which depends only on openssl via dexador so that we no longer need curl
  4. enable quicklisp-https-always whenever you load quicklisp e.g. in ~/.sbclrc

Once you have code locally other lisp implementations (e.g. those that
lack working https) can use the code as well, though sbcl is required
to retrieve any new code.

There are ways this could be made more robust, such as removing the
http method from quicklisp entirely so that there is no risk of http
being used by accident.

In the examples below you should adjust paths to match your system.

mkdir /tmp/bootstrap-ql-https
pushd /tmp/bootstrap-ql-https

git clone --branch version-2021-02-13 --depth=1 https://github.com/quicklisp/quicklisp-client.git quicklisp
git clone --depth=1 https://github.com/rudolfochrist/ql-https.git /tmp/ql-https

# when using docker this step can be run with networking disabled to ensure nothing accidentally leaks
sbcl --no-userinit --non-interactive --load bootstrap-1.lisp

sbcl --core continue.core --no-userinit --non-interactive --load bootstrap-2.lisp

sbcl --no-userinit --non-interactive --load bootstrap-3.lisp

/tmp/bootstrap-ql-https/bootstrap-1.lisp

(asdf:initialize-source-registry
 (list :source-registry (list :tree #p"/tmp/bootstrap-ql-https/ql-https")
       (list :tree #p"/tmp/bootstrap-ql-https/quicklisp") :inherit-configuration))
(defpackage #:ql-setup)
; don't forget the trailing slash for files >_<
(defvar ql-setup::*quicklisp-home* (probe-file "/tmp/bootstrap-ql-https/quicklisp/"))
(load "/tmp/bootstrap-ql-https/ql-https/ql-setup.lisp")
(asdf:load-system :ql-https)
(save-lisp-and-die "/tmp/bootstrap-ql-https/continue.core" :purify nil)

/tmp/bootstrap-ql-https/bootstrap-2.lisp

(setf ql-https::*quietly-use-https* t)
(quicklisp:setup)
(ql:quickload :dexador)

/tmp/bootstrap-ql-https/bootstrap-3.lisp (contents also need to be in ~/.sbclrc)

(let ((quicklisp-init "/tmp/bootstrap-ql-https/quicklisp/setup.lisp"))
  (if (probe-file quicklisp-init)
      (load quicklisp-init)
      (error "path to quicklisp-init is missing!? ~a" quicklisp-init)))
#-dexador
(asdf:load-system :dexador :verbose nil)
#-dexador
(push :dexador *features*)
#-quicklisp-https-always
(asdf:load-system :quicklisp-https-always :verbose nil)
#-quicklisp-https-always
(push :quicklisp-https-always *features*)

/tmp/bootstrap-ql-https/quicklisp/local-projects/quicklisp-https-always/quicklisp-https-always.lisp

(defpackage quicklisp-https-always
  (:use :cl)
  (:export :setup))

(in-package :quicklisp-https-always)

#+quicklisp
(defun fetch-via-dexador (url file &key (follow-redirects t) quietly (maximum-redirects 10))
  "Request URL and write the body of the response to FILE."
  (declare (ignorable follow-redirects quietly maximum-redirects))
  (let ((url-obj (ql-http:url url)))
    (setf (ql-http::scheme url-obj) "https")
    (let ((url-string (ql-http::urlstring url-obj)))
      (format t "FETCHING VIA dex: ~s~%" url-string) ; comment out this line if you are confident that https is working
      (dex:fetch url-string file :if-exists :supersede)))
  (values (make-instance 'ql-http::header :status 200)
          (probe-file file)))

(defun setup (&key (overwirte t) (methods '("https" "http")))
  (declare (ignorable overwirte methods))
  #+quicklisp
  (dolist (x methods)
    (when (or (not (find x ql-http:*fetch-scheme-functions* :test 'equal :key 'first))
              overwirte)
      (setf ql-http:*fetch-scheme-functions*
            (acons x 'fetch-via-dexador
                   (remove x ql-http:*fetch-scheme-functions* :key 'first :test 'equal))))))

(setup)

/tmp/bootstrap-ql-https/quicklisp/local-projects/quicklisp-https-always/quicklisp-https-always.asd

(in-package :asdf-user)

(defsystem quicklisp-https-always
  :version "0.0.0"
  :author "Tom Gillespie" ; adapted from "SANO Masatoshi"
  :license "MIT"
  :depends-on (:dexador)
  :components ((:file "quicklisp-https-always"))
  :description "Patch to force quicklisp to always use https. Adapted from quicklisp-https.")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests