I saw a lot of pain yesterday. I will see more pain today.

Pain from women saying that it’s back to the whisper network for them. Pain from women acknowledging the many faults of whisper networks.

Pain from women who do not want to be chilled — and who yet find themselves in the far north, with the wolves circling.

Pain from women who have seen their colleagues fail them before, and before, and before — and who have less hope now that the future of libraries will be any better.

Pain from women who fear that licenses were issued yesterday — licenses to maintain the status quo, licenses to grind away the hopes and dreams of those women in libraries who want to change the world (or who simply want to catalog books in peace and go home at the end of the day).

Above all, pain from women whose words are now constrained by the full force of the law — and who are now the target of every passerby who has much time and little empathy.

I will speak plainly: Lisa Rabey and nina de jesus did a brave thing, a thing that could never have rebounded to their personal advantage no matter the outcome of the lawsuit. I respect them, and I wish them whatever peace they can find after this.

I will speak bluntly to men in the library profession: regardless of what you think of the case that ended yesterday — regardless of what you think of Joe Murphy’s actions or of the actions of Team Harpy — sexual harassment in our profession is real; the pain our colleagues experience due to it is real.

It remains an unsolved problem.

It remains our unsolved problem.

We must do our part to fix it.

Not sure how? Neither am I. But at least as librarians and library workers, we have access to plenty of tools to learn, to listen.

Time to roll up our sleeves.

The other day I made this blog, galencharlton.com/blog/, HTTPS-only.  In other words, if Eve want to sniff what Bob is reading on my blog, she’ll need to do more than just capture packets between my blog and Bob’s computer to do so.

This is not bulletproof: perhaps Eve is in possession of truly spectacular computing capabilities or a breakthrough in cryptography and can break the ciphers. Perhaps she works for any of the sites that host external images, fonts, or analytics for my blog and has access to their server logs containing referrer headers information.  Currently these sites are Flickr (images), Gravatar (more images), Google (fonts) or WordPress (site stats – I will be changing this soon, however). Or perhaps she’s installed a keylogger on Bob’s computer, in which case anything I do to protect Bob is moot.

Or perhaps I am Eve and I’ve set up a dastardly plan to entrap people by recording when they read about MARC records, then showing up at Linked Data conferences and disclosing that activity.  Or vice versa. (Note: I will not actually do this.)

So, yes – protecting the privacy of one’s website visitors is hard; often the best we can do is be better at it than we were yesterday.

To that end, here are some notes on how I made my blog require HTTPS.

Certificates

I got my SSL certificate from Gandi.net. Why them?  Their price was OK, I already register my domains through them, and I like their corporate philosophy: they support a number of free and open source software projects; they’re not annoying about up-selling, and they have never (to my knowledge) run sexist advertising, unlikely some of their larger and more well-known competitors. But there are, of course, plenty of options for getting SSL certificates, and once Let’s Encrypt is in production, it should be both cheaper and easier for me to replace the certs next year.

I have three subdomains of galencharlton.com that I wanted a certificate for, so I decided to get a multi-domain certificate.  I consulted this tutorial by rtCamp to generate the CSR.

After following the tutorial to create a modified version of openssl.conf specifying the subjectAltName values I needed, I generated a new private key and a certificate-signing request as follows:

openssl req -new -key galencharlton.com.key \
  -out galencharlton.com.csr \
  -config galencharlton.com.cnf \
  -sha256

The openssl command asked me a few questions; the most important of which being the value to set the common name (CN) field; I used “galencharlton.com” for that, as that’s the primary domain that the certificate protects.

I then entered the text of the CSR into a form and paid the cost of the certificate.  Since I am a library techie, not a bank, I purchased a domain-validated certificate.  That means that all I had to prove to the certificate’s issuer that I had control of the three domains that the cert should cover.  That validation could have been done via email to an address at galencharlton.com or by inserting a special TXT field to the DNS zone file for galencharlton.com. I ended up choosing to go the route of placing a file on the web server whose contents and location were specified by the issuer; once they (or rather, their software) downloaded the test files, they had some assurance that I had control of the domain.

In due course, I got the certificate.  I put it and the intermediate cert specified by Gandi in the /etc/ssl/certs directory on my server and the private key in /etc/private/.

Operating System and Apache configuration

Various vulnerabilities in the OpenSSL library or in HTTPS itself have been identified and mitigated over the years: suffice it to say that it is a BEASTly CRIME to make a POODLE suffer a HeartBleed — or something like that.

To avoid the known problems, I wanted to ensure that I had a recent enough version of OpenSSL on the web server and had configured Apache to disable insecure protocols (e.g., SSLv3) and eschew bad ciphers.

The server in question is running Debian Squeeze LTS, but since OpenSSL 1.0.x is not currently packaged for that release, I ended up adding Wheezy to the APT repositories list and upgrading the openssl and apache2 packages.

For the latter, after some Googling I ended up adapting the recommended Apache SSL virtualhost configuration from this blog post by Tim Janik.  Here’s what I ended up with:

<VirtualHost _default_:443>
    ServerAdmin gmc@galencharlton.com
    DocumentRoot /var/www/galencharlton.com
    ServerName galencharlton.com
    ServerAlias www.galencharlton.com

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/galencharlton.com.crt
    SSLCertificateChainFile /etc/ssl/certs/GandiStandardSSLCA2.pem
    SSLCertificateKeyFile /etc/ssl/private/galencharlton.com.key
    Header add Strict-Transport-Security "max-age=15552000"

    # No POODLE
    SSLProtocol all -SSLv2 -SSLv3 +TLSv1.1 +TLSv1.2
    SSLHonorCipherOrder on
    SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+
aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+AESGCM EECDH EDH+AESGCM EDH+aRSA HIGH !MEDIUM !LOW !aNULL !eNULL
!LOW !RC4 !MD5 !EXP !PSK !SRP !DSS"

</VirtualHost>

I also wanted to make sure that folks coming in via old HTTP links would get permanently redirected to the HTTPS site:

<VirtualHost *:80>
    ServerName galencharlton.com
    Redirect 301 / https://galencharlton.com/
</VirtualHost>

<VirtualHost *:80>
    ServerName www.galencharlton.com
    Redirect 301 / https://www.galencharlton.com/
</VirtualHost>

Checking my work

I’m a big fan of the Qualsys SSL Labs server test tool, which does a number of things to test how well a given website implements HTTPS:

  • Identifying issues with the certificate chain
  • Whether it supports vulnerable protocol versions such as SSLv3
  • Whether it supports – and request – use of sufficiently strong ciphers.
  • Whether it is vulnerable to common attacks.

Suffice it to say that I required a couple iterations to get the Apache configuration just right.

WordPress

To be fully protected, all of the content embedded on a web page served via HTTPS must also be served via HTTPS.  In other words, this means that image URLs should require HTTPS – and the redirects in the Apache config are not enough.  Here is the sledgehammer I used to update image links in the blog posts:

create table bkp_posts as select * from wp_posts;

begin;
update wp_posts set post_content = replace(post_content, 'http://galen', 'https://galen') where post_content like '%http://galen%';
commit;

Whee!

I also needed to tweak a couple plugins to use HTTPS rather than HTTP to embed their icons or fetch JavaScript.

Finishing touches

In the course of testing, I discovered a couple more things to tweak:

  • The web sever had been using Apache’s mod_php5filter – I no longer remember why – and that was causing some issues when attempting to load the WordPress dashboard.  Switching to mod_php5 resolved that.
  • My domain ownership proof on keybase.io failed after the switch to HTTPS.  I eventually tracked that down to the fact that keybase.io doesn’t have a bunch of intermediate certificates in its certificate store that many browsers do. I resolved this by adding a cross-signed intermediate certificate to the file referenced by SSLCertificateChainFile in the Apache config above.

My blog now has an A+ score from SSL Labs. Yay!  Of course, it’s important to remember that this is not a static state of affairs – another big OpenSSL or HTTPS protocol vulnerability could turn that grade to an F.  In other words, it’s a good idea to test one’s website periodically.

Declaration of Independence.

Frederick Douglass: Oration, Delivered in Corinthian Hall, Rochester, by Frederick Douglass, July 5th, 1852.

Ulysses S. Grant: The Siege of Vicksburg (chapter 37 of the Personal Memoirs of U.S. Grant).

Treaty of General Relations of American and the Republic of the Philippines. Signed at Manila, on 4 July 1946 [PDF].

Martin Luther King, Jr.: The American Dream (sermon given on 4 July 1965 at the Ebenezer Baptist Church, Atlanta, Georgia).

W. Caleb McDaniel: To Be Born On The Fourth Of July. Published by Ta-Nehisi Coates.

Video Game Cats
CC-BY-NC-ND image “Video Game Cats” by jenbooks on Flckr.

VideoGameCat is a website that “aims to be a resource for educators and librarians interested in using games in educational environments, whether in class or as part of a library collection.” It’s been quiet for a while, but it’s now back with a new design.  The review editor (and former classmate of mine), Shannon Farrell of the University of Minnesota, is looking for folks to contribute reviews and guest posts.

I’m a gamer and a library professional, and I also think that games have a place in collection development policies. There are of course plenty of places on the web to go to find video game reviews, but it’s not every review site that has the information needs of a collection development librarian in mind.

If you’ve been thinking of writing up the last game you’ve finished (or perhaps thrown against the wall!) or introduced in your library, please consider checking VideoGameCat’s page for new reviewers and submitting your review.

Apologies to Ranganathan.

Say you have a Git repository you want to publish, and you’ve set up a Gitweb for it at http://git.example.com/?p=myrepo.git;a=summary.  So far, so good: others can browse your commits and download packages and tarballs.  Suppose you’ve also configured git-daemon(1) to publish the repo using the Git protocol.  Great!  Now suppose you’ve told the world to go to http://git.example.com. The world looks at what you have wrought, and then asks: How can we clone your repository?

Even assuming that you’ve used the default options in your git-daemon configuration, the Git clone URL could be any of the following depending on where your OS distribution’s packagers decided to put things:

  • git://git.example.com/myrepo
  • git://git.example.com/myrepo.git
  • git://git.example.com/git/myrepo
  • git:/git.example.com/git/myrepo.git
  • and there are even more possibilities if you did tweak the config

The rub is that Gitweb doesn’t know and can’t know until you tell it.  If you don’t tell it, somebody who wants to clone your repo and who is looking at the Gitweb page can only guess.  If they guess wrong a few times, they may give up.

Fortunately, the solution is easy: to make the Git clone URL display in your Gitweb, go to the repository’s base directory and create a new file called cloneurl and enter the correct clone URL(s), one per line. While you’re at it, make sure that the description file is accurate as well.

I saw a particularly annoying form of comment spam in Dorothea Salo’s excellent summary of various kinds of open information:

screenshot of plagiaristic comment spam
screenshot of plagiaristic comment spam

The author link points to the site of what appears to be a Turkish dietary supplement vendor.  Just a bit off-topic, unless this is somehow a subtle way of announcing that they’re releasing their supplement under an open recipe license.  What really steams me: the text was copied from one of my comments on the post.

Failing grade for plagiarism.