Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: administration

  • Chronic Infections: Blacklisted

    Chronic Infections: Blacklisted

    If you use Chrome, you may be used to those warnings about how a site is dangerous (or hacked) and maybe you shouldn’t visit it. If that happened to your site, you’d get an email if you use Google Webmasters (which I recommend you do), and then after you clean it up you can ask for a rescan. Or if you don’t, Google will rescan the site after a while and if it’s clean, carry on.

    That ends.

    Google found out something we’ve all known for a while, and that’s people can be evil and malicious. And what they’ve done is created a ‘repeat offenders’ blacklist, for sites that clean up only to allow themselves to be reinfected. As they say, “Sites that repeatedly switch between compliant and noncompliant behavior within a short window of time will be classified as Repeat Offenders.”.

    This is dangerous for users when a hack is outside their control.

    The number one cause of reinfections is not plugging the hole. In the case of things like WordPress, it’s down to upgrading everything, deleting anything with a known hack or backdoor, and locking down users. Hacks like Pharma, where the database becomes vulnerable and repeatedly re-infects a site, are thankfully rare for WordPress, but the same cannot be said of other CMS applications.

    And far worse than that is this. By which I mean what happens when your ad network is the cause of a hack?

    Recently, a friend of mine was hacked and got upset that his webhost’s scan of his site said it was clean, while Google did not. In looking at the site, I pointed out the hack was from his ads and not the files on the webhost. His webhost’s scanner didn’t hook into Google’s Safe Browsing service so of course it didn’t come up. He was pissed off about the host missing it, but once I explained why, he realized the magnitude of the issue.

    By adding an ad service to your site, you’re effectively trusting their behavior. And some ads are pretty scummy. While Google Adsense (and others) are usually pretty quick to kick-ban those idiots, the damage will be pretty hardcode. It takes but a small moment for a high-traffic site to serve up enough malware to make that attacker’s plan worthwhile. And worse, if the same kind of person get in again and again (which happens) and your site is infected multiple times, you will end of on the shit-list.

    Thats enough FUD on it. Let’s talk about mitigations.

    We’re all going to need to get better at figuring out where the malware is from. All of us. Security companies are going to lose money if they can’t stop repeat attacks, and since even the best firewall can’t stop shitty ads, all our scanner tools are going to need to be better about detecting what the cause is and where it’s from. This is going to be hard, since the ad may be gone by the time the site scan runs.

    Google will need to tell us what they know a lot better. I don’t know if they will, but they’ll need to figure something out. At the same time, I get why they may not want to. It tips the hand to tell malicious people exactly how you caught on to them, but at the same time telling people “Your ads are serving up malware” would be impactful and hopefully not too harmful. I’m on the fence there.

    Finally, we all know ads on the internet are shit. We’re all barely making money off them. So if you get infected by an ad vendor twice, it’s time to turn those ads off and look for something new. If that ad vendor is Google, open a ticket with them and provide evidence that they’re hurting your SEO and could cause you to get on that repeat offender list.

    Yes, this is making a hard decision, but it’s one you must make. If you’re being betrayed by your ads, you need to quit them.

  • Mailbag: Curbing Comments By Count

    Mailbag: Curbing Comments By Count

    Someone had a rant in my mailbox about my strong stance on comment moderation, which can be distilled to this question:

    I noticed you really have strong opinions on comment moderation. Do you use anything other than bad words to flag for moderation or outright block?

    Sure do!

    I’m very careful about ‘bad words’ since ‘anal’ will also pick up ‘canal’ and I only moderate for for things that are generally only used as a pejorative. Example? Okay, I have ‘dyke’ and ‘kike’ in my mod list. The first one I get called a lot. Still. The second has fallen out of favor. But because people have a remarkable talent to say words with the sole intent to be hurtful, even under the veneer of “I was just being funny, stop being so sensitive!” I have cherry-picked the popular ones on my sites and tossed them into moderation.

    The only thing I blacklist are people. People’s emails (and user names sometimes) go into the blacklist. That’s why I wrote Sitewide Comment Control, I’m able to blacklist people from the whole network easily. But I only use this for people. People should be blacklisted when they prove themselves to be untrainable.

    That leaves one thing up in the air and that’s moderation. You have three choices with default WordPress: Moderate all, moderate un-approved, moderate none.

    I have “moderate un-approved” which means I have to manually approve all first time comments. To add on to that, I use Comment Probation in order to restrict people I’m not entirely sure about.

    And finally, I moderate by length.

    I month ago, I mentioned on Twitter that I was playing with an idea to have my comments moderated by length. If a comment was over X words long, it should be flagged as needing approval before showing.

    Caspar Hübinger, in the time it took me to get a cup of coffee, wrote Comment Moderation by Word Count. I made one, small, patch to it, and I’m using it now.

    This simple WordPress plugin will send any comment that would otherwise be approved automatically by WordPress to the moderation queue if it contains more than a given number of words.

    The theory I have is this: If your comment is over a certain length, you really may want to consider making it a rebuttal blog post of your own. My limit is currently set to 250 words here, which is half a page of content.

    Mod by comment length is a very basic field on your Comment Settings section

    My one change was this:

    If current_user_can( 'edit_posts' ) then they should be able to leave a comment of any length without moderation.

    My theory here was that admins and editors are trusted users.

    And now you know!

  • Static Content Subdomain

    Static Content Subdomain

    I use a lot of different tools to run my websites, and over time I’ve learned what I want is to have my static content, the files that are uploaded and are images, stored separately from my apps. So while I have the basic folders on my domain (wordpress, wiki, gallery) I have a special subdomain called static.example.com for all those images and videos.

    There are a few reasons I do this. First, I like having my images separate. Second, it allows me to establish a cookie-free subdomain for images and that shuts up YSlow’s check.

    Create The Subdomain

    Do this however your host allows. Keep in mind that some don’t allow you to traverse domain folders. If your host creates your domain as /home/user/example.com and subdomains as /home/user/static.example.com you may have to fight a little more with things depending on your setup. If possible, I prefer to put the subdomain folder inside the main web root.

    If you’re using cPanel, by default you get your static subdomain installed at /home/user/public_html/static which is how I like it. This is perfectly accessible by all things but it’s also browsable at example.com/static/ and we don’t want that. Applying a little .htaccess magic will solve this.

    # CDN
    <If "%{HTTP_HOST} == 'example.com' ">
            RedirectMatch ^/static/(.*)$ http://static.example.com/$1
    </If>
    

    Now we’re ready to go!

    Move WordPress Uploads

    This used to be really easy. Go to Settings -> Media and change things. But we removed that to stop people from blowing themselves up. Now there are a couple ways about it. I jumped right over to editing the options by going to wp-admin/options.php and look for upload_path and upload_url_path.

    Setting image location options

    I change upload_path to /home/example/public_html/static/wordpress which is where I’ve moved all my images. Then upload_url_path becomes http://static.example.com/wordpress and I’m done except for fixing my old posts. It’s actually pretty neat that once I put those paths in, the Media Settings page lists them as editable.

    Fixing the old posts takes a little trick though, and you’ll have to search/replace your posts via the database:

    UPDATE wp_posts SET post_content = REPLACE(post_content,'http://example.com/wp-content/uploads/','http://static.example.com/wordpress/');
    

    Or in wp-cli:

    wp search-replace http://example.com/wordpress/wp-content/uploads http://example.com/wordpress
    

    The gotcha here is that since I use SSL for my administration, I had to set up a new certificate for the static domain. Not a big deal right now since I can set up a self-signed, or use StartSSL until Let’s Encrypt is off the ground. It is something to consider though.

    Move ZenPhoto Uploads

    I have to start by warning you that Zenphoto doesn’t like this. When you install it, it puts your images in an albums folder, in the Zenphoto gallery install. This isn’t so bad, but you actually can move it around. You have to look in your zenphoto.cfg.php file (found in zp-data). The default location for your albums is defined by this:

    $conf['album_folder'] = '/albums/';
    $conf['album_folder_class'] = 'std';
    

    Since I want it in the static location, I tell it my folder path based on ‘web root’ and that its ‘in_webpath’ (which tells ZenPhoto to look in the root and not relative), by changing that section to this:

    $conf['album_folder'] = '/static/gallery/albums/';
    $conf['album_folder_class'] = 'in_webpath';
    

    But that means my URLs for images become http://example.com/static/gallery/albums... and I wanted http://static.example.com/gallery/albums... instead. Thankfully the .htaccess rule I used at the beginning of all this covers me there. Looking into this, I understand this is the case because unlike MediaWiki or WordPress, ZenPhoto only has one ‘location’ setting. The other two have path and URL.

    MediaWiki

    This was … weird. Technically all you have to do is set up the folders and change the following values in LocalSettings.php:

    $wgUploadPath       = "/static/wiki";
    $wgUploadDirectory  = "/home/example/public_html/static/wiki/";
    

    The thing that’s weird is that the documentation says you can do this:

    $wgUploadPath       = "http://static.example.com/wiki";
    

    And when you do, the image URLs properly call from the domain name. They just won’t load. When you dig deeper, it turns out that it’s caused by the settings for responsive images. The way it puts in srcset doesn’t seem to like this. So for now I’ve disabled it and my setup is this:

    $wgUploadPath       = "http://static.example.com/wiki";
    $wgUploadDirectory  = "/home/example/public_html/static/wiki/";
    $wgResponsiveImages = false;
    

    End Result?

    All my uploaded content is on my ‘static’ subdomain, separate from everything else, which makes version control even easier. Also now if I ever decide to move things off to a CDN, I’m pretty well set up.

    The real reason I do this is that while some of my content is uploaded via the content management systems I use (WordPress, ZenPhoto, etc), the majority is not. ZenPhoto, for example, is faster to FTP up a gig of images than it is to use a PHP tool. Ditto videos. And because of them, it’s nice to have a separate location I can give access to without allowing someone full rights on all my tools.

  • Make or Break Yourself

    Make or Break Yourself

    How you react to adverse situations is what makes or breaks your business, not the fact that you had one in the first place.

    Taylor Swift recently penned an open letter to Apple Music. To Apple, Love Taylor lets us all in on a fact of the new Apple Music (their streaming service, coming soon for free for 3 months) that a lot of us didn’t know.

    I’m sure you are aware that Apple Music will be offering a free 3 month trial to anyone who signs up for the service. I’m not sure you know that Apple Music will not be paying writers, producers, or artists for those three months. I find it to be shocking, disappointing, and completely unlike this historically progressive and generous company.

    Three months where we get free music is great, but the cost of that free music was astronomical. As Taylor points out, it doesn’t hurt her, she has money. But the indie people will be terribly hurt by this, to the point that many of my indie friends pulled out of the trial too.

    Apple kowtowed in under 24 hours from that post. Eddie Cue (who’s the Apple mogul in charge of this project) replied on Twitter:

    I see a lot of people take criticism in some pretty appalling ways. I’ve been threatened with legal action for not deleting a one-star review of a plugin on WordPress.org. I’ve been vilified, called a Nazi or worse, and had my reputation blasted because I stood up for a user who didn’t like a product and left a bad review. I get insulted daily because I tell people “If someone misunderstood what your documentation said, you need to review your docs and consider updating them.”

    I’m glad I have a thick skin, because some days the things people say and accuse me of would make me cry. Sometimes they do, and those are the days I walk away and let someone else handle that person, or just take a break.

    In general, I believe in the inherent capability of goodness in humanity. I assume good faith. I presume that people who are leaving reviews aren’t generally doing it to attack me personally, but because they’re having a terrible day. Maybe they’re having the worst day of their life. And I, as an experienced support tech, know that they’re pretty much always going to be irrational.

    That’s the thing. People aren’t usually intentionally misleading, nor do they plan to make my life miserable. They’re having a bad day and it’s perceived to be my fault, so I’m sorry, but let me try to understand things better. How I reply to them depends on how they come to me with their issues, though. If they say ‘it’s broken!” (a common complaint, right?), I tell them I’m sorry and ask them if they can explain what, exactly, is broken. I may spend time clarifying with them “Do you mean X?” and I may ask “Why are you trying to do Y?” so I can understand the big picture.

    And then… those people who come at me and say “This person is lying and gave me a bad review!” I’m often inclined to side with the users, since a bad review is something that makes people overreact. But that doesn’t mean I dismiss the complaint out of hand. I check if the reviewer is a fake account (we have ways), and I check their history and their information and validate they’re real people before I reply. If they’re fake, I remove the reviews. If they’re not, I leave them be.

    Leaving them be is where most (if not all) of the hate comes from. You see, leaving them be is hurting businesses and ruining reputations.

    No. No they’re not.

    What ruins your reputation is how you reply to them. If you accuse them of being spammers or harassers, you make yourself look bad. If you lay into them because you disagree with their review, you make a fool of yourself. A review is a ‘how I feel’ from a user, and even though you may not agree with their conclusions, that doesn’t make their experience invalid. It means there was a breakdown in communication somewhere between you and them.

    This is why I tell people to check their documentation. If they’re getting a lot of bad reviews that are plain wrong, and they’re wasting a lot of time talking to people and correcting them, then the issue has to be, in part, the information they’ve presented up front. If its not there, add it. If it’s there, point them to it. “Actually I answered this in the FAQ where it says this plugin is Multisite only.” True story, I have to use that a lot.

    But when that question comes up time and again, I may ask “The FAQ covers this here LINK. Do you think there’s a better place I can put that? Where were you looking so I can make it more obvious for the next guy?”

    Maybe they never reply and fix that one-star review, but when people go and look at the reviews and see a one-star, and read it, they’ll see my mature, reasonable, honest reply. And that will do far more for my reputation than anything else.

  • Mailbag: Wrong Robots

    Mailbag: Wrong Robots

    I got an odd email from ‘Yan’ who, amidst the odd hate and sexist filled remarks that apparently I don’t like people in the WP community, had a legit question:

    Seen your post:

    But… Your actual robots.txt does not reflect the content of the article. Hmmm…

    Well. That was almost 2 years ago. And it never reflected the content of this site. I don’t care if this site has it’s images snagged. I have anti-hotlinking protection in my .htaccess anyway. It’s my other site, my massively major huge gallery with 10G of photos that I protect.

    That brings up a point that many people miss about this site. I’m not always talking about what I do here. For example, I talked about making a slide-up bit of code that duplicates WordPress.com’s follow tab. That email setup isn’t here and it never will be. I’m not particularly worried about my followers’ ability to find the sidebar email registration box there. This is a site for slightly more technical people.

    However, the site that code is on is a site visited by luddites, primarily. They want their news about their thing in a way that is simple, straightforward, and easy. They need a reminder. Also they share links on social media a lot, so making a slide-up that auto-pops when you come from Facebook or Tumblr or Twitter was the right choice to make sure people knew what was going on and how to sign up. It’s had amazing results.

    There are lessons I learn from running multiple sites and I bring them all back here to people who would appreciate them.

    Now if people wonder, yes I do think that Google’s still evil for how they hotlink images. Of course, I’d think them equally evil for copying my images. Image search is just a really messy thing. The two options you get for it is that either Google has a copy of all the images on the planet or they hotlink. Even assuming they’re clever enough to protect themselves from duplicate images using some sort of super powerful algorithm, you get those options and each has a problem. If you’ve copied everything, you have to have a file server the likes of which would make the pyramids look teeny tiny, and in both cases you need a database with enough speed to stop us all from running Google Pagespeed tests on Google.

    Am I the only one who does that? Oh. Sorry.

    We’re talking about Google being evil and robots.txt files. The site that I do block Google Images on has a very large robots:

    User-Agent: *
    # My stuff
    Disallow: /cgi_bin/
    
    # WordPress
    Disallow: /trackback/
    Disallow: /blog/
    Disallow: /wp/
    Disallow: /wordpress/wp-admin/
    Disallow: /wordpress/wp-includes/
    Disallow: /wordpress/xmlrpc.php
    Disallow: /wp-admin/
    Disallow: /wp-content/
    Disallow: /wp-includes/
    Disallow: /xmlrpc.php
    Disallow: /wp-
    
    # Gallery
    Disallow: /gallery/albums/
    Disallow: /gallery/themes/
    Disallow: /gallery/zp-core/
    Disallow: /gallery/zp-data/
    Disallow: /gallery/page/search/
    Disallow: /gallery/uploaded/
    Disallow: /gallery/rss.php
    Disallow: /gallery/rss-comments.php
    Disallow: /gallery/README.html
    Disallow: /gallery/rss-news-comments.php
    Disallow: /gallery/rss-news.php
    
    # Wiki
    Disallow: /wiki/images/
    Disallow: /wiki/bin/
    Disallow: /wiki/cache/
    Disallow: /wiki/config/
    Disallow: /wiki/docs/
    Disallow: /wiki/extensions/
    Disallow: /wiki/languages/
    Disallow: /wiki/maintenance/
    Disallow: /wiki/math/
    Disallow: /wiki/public/
    Disallow: /wiki/serialized/
    Disallow: /wiki/tests/
    Disallow: /wiki/skins/
    Disallow: /wiki/t/
    Disallow: /wiki/index.php
    
    User-agent: Mediapartners-Google
    Allow: /
    
    User-agent: Adsbot-Google
    Allow: /
    
    User-agent: Googlebot-Image
    Disallow: /
    
    User-agent: Googlebot-Mobile
    Allow: /
    
    User-agent: Browsershots
    Allow: /
    
    User-agent: Dotbot
    Allow: / 
    

    So yes, actually, I am still using that code. There you are.

  • Learning nginx

    Learning nginx

    I’m an nginx rookie. In fact, I moved a site specifically to nginx so I could sit and learn it. While this site, today, is ‘on’ nginx, it’s actually an nginx proxy that sits in front of Apache 2.4, not because I think Apache is necessarily better, but because after all this time, I still can’t stand the loss of the dynamism of my .htaccess.

    When I was experimenting, though, one of the things I started to do was recreate my ‘tinfoil hat’ .htaccess rules in nginx. What are ‘tinfoil hat rules’? They’re things I’ve tweaked in .htaccess to make it harder for nefarious people to look at my code and get into my servers. They’re also general ‘stop being from being jerks’ rules (like preventing hotlinking).

    This isn’t complete, but it’s everything I’d started to compile and test.

    Header

    ######################
    # TinFoil Hat Rules
    

    This is pretty basic, I like to document my section before I get too far into this.

    Directory Listing

    # Directory Index Off
    location  /  {
      autoindex  on;
    }
    

    Directory listing is like when you go to domain.com/images/ and you get a list of all their images. This is just a bad idea, as people can also use it to list PHP files you might have (many plugins lack an index.php, and no, this isn’t a bad thing). This simple rule will protect you.

    Hotlinking

    # Hotlinking
    location ~* (.jpg|.png|.jpeg|.gif)$ {
        valid_referers blocked elftest.net *.elftest.net;
        if ($invalid_referer) {
            return 444;
        }
    }
    

    Ah. Hotlinking. This is in-line using images from someone else’s server, like <img src="http://example.com/images/yourimage.jpg" /> – If I’m on example.com, that’s fine. If I’m not then that’s bad. Never ever hotlink images unless the site provides you a hotlinking URL. I cannot stress this enough.

    This code comes straight from the nginx wiki, and works great.

    Protecting wp-config.php

    This is pretty straightforward. I want to block anyone from hitting that directly, any time, any where.

    location /wp-config.php {
        deny all;
    }
    

    Done.

    Brute Force Protection

    If you have ngx_http_limit_req_module module then you can rate-limit how many requests an IP can give to a file.

    location /wp-login.php {
        limit_req zone=one burst=5;
    }
    

    And that’s all I got to…

    And that is, sadly, as far as I got before I started playing with Apache 2.4 and enjoying the ifs of that, over nginx. What about you? What are your nginx security tweaks?