Christians Tagebuch: web

The latest posts in full-text for feed readers.


Running TYPO3 in a subdirectory

At work we're running a couple of composer-based TYPO3 v11 instances in a subdirectory instead of the root path of domains, e.g. https://example.org/info/ instead of https://example.org/. We do this because the main web application runs on /, while /info/ serves editor-editable content.

The setup consists of 2 servers/containers. One serves the main web application on https://example.org/ and proxies all /info/ requests to the second web server. The second web server delivers a TYPO3 instance.

It's more complicated than the average reverse proxy setup. In production, the initial proxying is done by AWS Cloudfront - and that does not support stripping paths when proxying.

Main webserver

Relevant Apache 2.4 site configuration:


    ServerName example.org
    [...]
    ProxyPass        "/info/" "http://typo3.example.org/info/"
    ProxyPassReverse "/info/" "http://typo3.example.org/info/"

]]>

TYPO3 webserver

Apache site configuration:


    ServerName example.org
    ServerAlias typo3.example.org
    UseCanonicalName On

    [standard typo3 configuration follows]

    
        # Reverse Proxy configuration in Terraform does not allow to
        # proxy "/info/" to "/" - it maps "/info/" to "/info/"
        # So we need to remove that.
        # Also requires REQUEST_URI modification in AdditionalConfiguration.php
        RewriteRule "^info/(.*)" "$1"
    

]]>

TYPO3's site configuration is configured to have /info/ in the base path:

config/sites/example/config.yaml
base: 'https://example.org/info/'

TYPO3 also needs to know that it's running in a reverse proxy setup:

public/typo3conf/LocalConfiguration.php
 [
        //[...]
        'reverseProxyHeaderMultiValue' => 'first',
        'reverseProxyIP' => '172.17.190.*,127.0.0.1',
        'reverseProxyPrefix' => '/info',
        'reverseProxySSL' => '172.17.190.',
    ]
];
]]>

And at last, we rewrite the request URI variable used by TYPO3:

public/typo3conf/AdditionalConfiguration.php

Local setup

The setup above requires two servers/containers, which is fine for production. Local development setup is a bit simpler; we use one container with two different domains:

example-proxy.test

Used for the main webserver.

We access TYPO3 frontend at http://example-proxy.test/info/, and the backend at http://example-proxy.test/info/typo3/.

It proxies to http://example.test/info/.

example.test

Runs TYPO3

Published on 2025-04-10 in ,


Wordpress registration spam

Spammers are using Wordpress installations with open registration to send spam e-mails to uninvolved users.

The mails are sent via the "Register" function that is linked on the Wordpress login page wp-login.php. The registration form has two fields: "Username" and "Email".

The username allows spaces, and this is where the spammers input a domain name and a promotional text. The domain name gets auto-linked by e-mail clients, making it easy for users to go to the spammer's site.

Such a spammy Wordpress registration e-mail looks like this:

Subject: [Legit site] Login Details
Username: www.spammer.example.com - 1.2342 BTC

To set your password, visit the following address:

https://legitsite.example.net/wp-login.php?login=www.spammer.example.com%20-%201.2342%20BTC&key=oSxUtw01QIFHoxHvokfd&action=rp

https://legitsite.example.net/wp-login.php

Everything after the Username: in that line is provided by the spammer.

Two things should be fixed here by Wordpress:

  • Reject usernames with spaces
  • Reject usernames that have "www." in them, because that causes the e-mail clients to autolink the URL

Let's see what the Wordpress developers say to my ticket.

Others with this problem

2024-11: Reddit: Spammed with 100+ Fake WordPress Login Emails (Help!)

Published on 2025-03-11 in ,


Apache+PHP: Content-Length header is missing

I received a photo in the Conversations XMPP app on my Android phone, but the image was not shown. Instead I got a message

Bildgröße auf xmpp-files.cweiske.de prüfen

which translates to

Checking image size on xmpp-files.cweiske.de

The other XMPP client Dino showed the images, though.

In Conversations bug report #240 it was observed that the Content-Length header was missing, and my server exhibited the same problem:

$ curl -I 'https://xmpp-files.cweiske.de/share_v2.php/23/42.jpg
HTTP/1.1 200 OK
Date: Sat, 08 Jun 2024 12:38:47 GMT
Server: Apache/2.4.59 (Debian)
Access-Control-Allow-Methods: GET, PUT, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 7200
Access-Control-Allow-Origin: *
Content-Security-Policy: "default-src 'none'"
X-Content-Security-Policy: "default-src 'none'"
X-WebKit-CSP: "default-src 'none'"
Content-Type: image/jpeg

No Content-Length. I'm using the mod_http_upload_external Prosody module for file uploads together with the share_v2.php provided by it. That PHP script does set a Content-Length header, but nobody receives it!

Even a PHP script that only sends out a Content-Length header does not work:

$ curl -I https://xmpp-files.cweiske.de/test.php
HTTP/1.1 200 OK
Date: Sat, 08 Jun 2024 13:18:34 GMT
Server: Apache/2.4.59 (Debian)
X-Test: 23
Content-Type: text/html; charset=UTF-8

The header is missing.

The cause

Then I found Apache bug report #68973: Content-Length header missing in 2.4.59 is a breaking change which explained the symptom I experienced:

Apache version 2.4.59 fixed security issue CVE-2024-24795 by preventing CGI-like scripts (such as PHP) from sending out Content-Length headers.

A new environment variable ap_trust_cgilike_cl was introduced that restores to the old behavior.

Solution

I re-enabled the Content-Length header in my PHP applications by creating an apache configuration file

/etc/apache2/conf-available/cweiske-content-length.conf
SetEnv ap_trust_cgilike_cl 1

enabling it and restarting apache2:

$ a2enconf cweiske-content-length
$ systemctl reload apache2

Published on 2024-06-08 in ,


"Have I been pwned" is unusable for me now

I've been using the Have I been pwned data breach information service since many years. After a failed attempt to sell the project, payment was introduced: First the API and now domain search.

"Domain search" means that I can see all e-mail addresses from my domain "cweiske.de" that were found in data breaches, and not only search for individual addresses.

20+ family members have an e-mail address on my server, and I use sub-addressing for nearly all services: Whenever I subscribe to a service "example.com", I register with the email address username+example.com@cweiske.de. In the case of a breach and even with spam, I do know where my e-mail address was gotten from.

This means that I have hundreds of unique e-mail addresses, and some of them are in data leaks.

With the HaveIbeenPwned pricing structure, I would have to pay 16.95 USD per month to see which e-mail addresses have been leaked. As a private person, this is way too much.

Now I'm in the situation that HIBP sends me e-mails about breaches on my domain:

An email on cweiske.de has been pwned in the Telegram Combolists data breach

.. but I have to pay to see which e-mail is affected.

So long, and thanks for all the fish.

Published on 2024-06-04 in


uBlock origin: Hide elements containing a certain element

Recently I had the need to hide elements on some web page, but only if they contain a certain other element: Hide all list items that have a div with class="premium".

I use Firefox with uBlock origin for advertisement blocking. Beside ad blocking, it also helps to keep sanity on the web by hiding unnecessary elements like the "hot network questions" list on Stack Overflow.

The normal filter rules used by uBlock are CSS selectors, which do not allow selecting elements based on child tags.

Fortunately, uBlock supports XPath filters which specifically have this feature. The resulting filter rule was easy to write:

##:xpath(//li[.//div[contains(@class,"premium")]])

heise+ filtering

2019

I use this to filter "heise plus" articles on the main heise.de page, since I do not have a login there and do not need teasers:

##:xpath(//article[.//span[contains(@class,"a-article-meta__item--heiseplus")]])

2023

The usage of Tailwind CSS makes it harder to block elements since we do not have meaningful class names anymore. Instead I have to rely on hard-coded element attributes.

##svg:xpath(.[@width=78 and @height=24]):upward(article)

e-reader-forum.de Anzeige

The owner of e-reader-forum.de put ads into their forum that look like normal posts. The first response to a new thread is

Hello $originalPosterName,

have a look here:
$originalThreadTitle

for example at thread Eigene Apps installieren (Firmware 14.2.0) it says (in German):

Hallo AaronDewes,

schau mal hier:
Eigene Apps installieren (Firmware 14.2.0).

The only way to know it's an ad is that the user name is "Anzeige", which is german for "Advertisement".

This is one of the most annoying ads I've seen in a long time, so I had to add a ublock rule that removes the posts that have "Anzeige" as username:

##:xpath(//article[contains(@class,"message--post") and .//span[contains(@class,"username") and text() = "Anzeige"]])

e-reader-forum with blocked advertisements

Published on 2019-02-10 in ,


Twitter shows notifications 28s after page load

I don't use Twitter very often and only check the website every couple of days. When I open a new tab, type twitter.com and press "enter", the website loads.

When I have a notification, the red circle badge on top of the "Notifications" menu entry appears for a fraction of a second and then disappears. It takes 28 seconds after the page has been loaded for it to re-appear.

When I click the notifications menu entry they are immediately visible and do not disappear.

I suspect this is done deliberately by Twitter to prevent people from closing the twitter tab in their browser. (nudging, dark pattern)

Twitter website when it has been loaded 28 seconds later: The unread notification badge appears

Published on 2022-03-30 in ,


Google broke my local domains

My laptop's name is boo, and all the web projects I'm developing on my laptop have a domain name $project.boo. Today I wanted to open http://archive.boo/ in Firefox and got an error message:

Kein Verbindungsversuch unternommen: Mögliches Sicherheitsproblem

Firefox hat ein mögliches Sicherheitsrisiko erkannt und daher archive.boo nicht aufgerufen, denn die Website benötigt eine verschlüsselte Verbindung.

archive.boo verwendet eine Sicherheitstechnologie namens "HTTP Strict Transport Security (HSTS)", durch welche Firefox nur über gesicherte Verbindungen mit der Website verbinden darf. Daher kann keine Ausnahme für die Website hinzugefügt werden.

My local Apache web server does not server any HSTS headers, and tracing the HTTP request in Wireshark shows me that no HTTP request is made at all. Only a HTTPS request.

It turns out that the .boo top level domain (TLD) is owned by Google and that it is on the HSTS preload list for both Firefox and Chromium.

Game over. I could try to disable HSTS in the browser (which I won't do), or I move to a new development TLD (that is specific to my machine, so I can share links in my network).

Published on 2022-02-17 in ,


curl: error setting certificate verify locations

Recently in a docker container I got the following error message:

cURL error (77) error setting certificate verify locations: CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs for https://example.org

The solution was to install the ca-certificates via apt.

Published on 2020-11-21 in ,


Laravel: Finding the route name

Recently at work I had to analyze a problem in a Laravel application that I was not familiar with. The problem: When calling a specific URL, it wrongly redirected to another URL.

The route that I expected to be called was not, and routes/web.php was huge; too large to find the matching route quickly.

The solution was to adjust public/index.php and add the following line before the response was sent back to the browser:

$response->header('X-Route', Route::currentRouteName());
$response->send();

Now I could look at the redirect's HTTP headers to find the route that had been used:

$ curl -I http://app.example.org/en/explanatory-videos/test-510/
HTTP/1.1 302 Found
Date: Wed, 16 Sep 2020 11:45:26 GMT
Server: nginx/1.10.3 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache, private
Location: http://app.example.org/en/products
X-Route: en_product_detail

Published on 2020-09-20 in ,


James Bond novels are public domain

The James Bond movies are based on novels written by Ian Fleming, and I discovered that all of his works entered the public domain in 2015.

While book retailers want 9€ per book (which themselves are not that long), the Internet Archive provides The Complete Ian Fleming as .epub file for download onto your e-book reader, for free.

I'm already the enjoying the first novel on my e-reader.

Contents of the e-book

  • 007 in New York
  • Casino Royale
  • Chitty Chitty Bang Bang
  • Diamonds are Forever
  • Dr. No
  • For Your Eyes Only
  • From Russia with Love
  • From a View to a Kill
  • Goldfinger
  • Live and Let Die
  • Moonraker
  • Octopussy
  • On Her Majesty’s Secret Service
  • Quantum of Solace
  • Risico
  • The Diamond Smugglers
  • The Hildebrand Rarity
  • The Living Daylights
  • The Man with the Golden Gun
  • The Property of a Lady
  • The Spy Who Loved Me
  • Thrilling Cities
  • Thunderball
  • You Only Live Twice

Published on 2019-09-10 in ,