2016年9月29日 星期四

在Windows的XAMPP上使用XDebug和Sublime調試PHP

如何在PHP上使用斷點除錯?
xdebug + remote debugging + one of the supported clients
這邊我的clients選sublime的XDebug Client 插件

Windows 7 上裝的 XAMPP 要怎麼開啟XDebug?
其實在你的D:\xampp資料夾下有文檔activate-use-xdebug.pdf
或直接開啟
http://localhost/dashboard/docs/activate-use-xdebug.html

文檔中有要你安裝 WinCacheGrind 去調試,裝了後不會用+介面太醜。放棄

打開D:/xampp/php/php.ini ,加入以下配置
[XDebug]
zend_extension = "D:\xampp\php\ext\php_xdebug.dll" => 使用xampp的xdebug時要這樣寫,配置 extension=php_xdebug.dll 無效
xdebug.profiler_append = 0
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = "D:\xampp\tmp"
xdebug.profiler_output_name = "cachegrind.out.%t-%s"
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_connect_back  = 1
xdebug.remote_port = 9000
xdebug.remote_log="D:\xampp\xdebug_log"

重啟Apache

打開phpinfo()後會看到

表示PHP的XDebug配置成功

安裝sublime XDebug Client
直接Package Control 搜尋XDebug Client 安裝

配置Sublime
要調試某一個項目,首先得把這個項目在sublime下保存成一個project (一直都有這習慣)
sublime->project->save project as ...

接下來配置專案
sublime->project->edit poject

設定檔類似以下內容:
{
    "folders":
    [
        {
            "path": "."
        }
    ],
    "settings": {
        "xdebug": {
             "url": "http://test.localhost/",
        }
    }
}

其中url是專案所在url,記得在hosts裡頭將這個url指向127.0.0.1,還有在apache的virtualhost裡將其指向專案根目錄
這樣就OK了,準備開啟調試吧
開啟調試
開啟調試方式也比較簡單,在想要加中斷點的地方右鍵
xdebug->Add/Remove breakpoint
這樣專案在運行到本行的時候就會停止下來
然後開始調試,在功能表列選擇
tools->xdebug->start debugging(launch browser)
sublime會自動打開瀏覽器,進入配置時寫的網站連結,進行調試

可能問題
無法跟蹤中斷點
這可能是xdebug埠被佔用,按Ctrl+`或者功能表列View->show Console查看錯誤資訊,有可能是xdebug埠已經被佔用的緣故。

我遇到的狀況是
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Bear\\AppData\\Roaming\\Sublime Text 3\\Packages\\Xdebug Client\\Xdebug.sublime-settings'
error: CodeFormatter
原來 C:\Users\Bear\AppData\Roaming\Sublime Text 3\Packages\Xdebug Client 沒這個目錄,手動新建目錄後, Preferences => Package settings => Xdebug => Setting - Default 儲存才能看到Xdebug.sublime-settings 被存到正確的位置。Xdebug.sublime-settings我用預設值,沒特別配置

Ethan 的XDebug
http://blog.xuite.net/ahdaa/blog1/42909643-%5BPHP%5DXdebug
Ethan配置的XDebug有像這篇一樣,在畫面上顯示堆疊,不過我覺得Sublime XDebug Client更好用,就不研究這篇了

在command line ( CLI )上調試XDebug + Sublime
https://github.com/martomo/SublimeTextXdebug/issues/3
Xdebug.sublime-settings 和 *.sublime-project 不用動
打開xampp的console,輸入
Windows
set XDEBUG_CONFIG="idekey=sublime.xdebug"
php myscript.php
UNIX
export XDEBUG_CONFIG="idekey=sublime.xdebug"
php myscript.php

下面這行沒設斷點,但也會跑進去,連跑兩次,第二次XDebug會crash掉
$this->oDB = &A::singleton( 'db', $aDBO );
&拿掉,改成
$this->oDB = A::singleton( 'db', $aDBO );
正常

注意:不能打開cygwin,因為cygwin的php沒有配置XDebug,可用php -m 檢查
注意: ubuntu的cli和fpm的php.ini是分開的,要在CLI除錯記得cli的php.ini也要加入xdebug的配置

Debug時觀察變數
所有的變數都在Xdebug Context 面板中
如何像chrome開發者工具的console一樣,觀察現在的變數?
右鍵 => XDebug => Set Watch Expression 或 Edit Watch Expression
然後在 XDebug Watch 面板中看結果

Debug時運算變數
如何像chrome開發者工具的console一樣,在斷點時運算變數(更改變數的值)?
(進入斷點)ctrl+shift+p  => 執行 XDebug: Session - Evaluate => 輸入框輸入PHP代碼。ex. $test= "123"; => ctrl + shift + F5 ( XDebug: Breakpoint - Run ) 
這樣子就會將$test的值改為"123"後往下跑

防止在Notice、Strict standards、Deprecated時被中斷(break)
Xdebug.sublime-settings ( Setting - Default ) break_on_exception 註解掉 "Notice"、"Strict standards"、"Deprecated"

使用start debugging(launch browser) 後網頁轉不出來
這是目前比較無解的一個情況,在使用CLI debug或要切專案debug時,常常發生start debugging(launch browser) 打開瀏覽器後,網頁疑似被斷點轉不出來,但sublime卻沒進斷點,無法繼續往下跑的現象
Sublime console ( Ctrl+` ) 報錯:
File "xdebug.helper.helper in C:\Users\User\AppData\Roaming\Sublime Text 3\Installed Packages\Xdebug Client.sublime-package", line 45, in base64_encode
UnicodeEncodeError: 'ascii' codec can't encode characters in position 381-384: ordinal not in range(128)
目前只能重開機去解這個問題。(一旦要換專案或cli時,就很容易發生這個問題)
改用sublime text 2的Xdebug Client
這個老外也有同樣的問題
https://github.com/martomo/SublimeTextXdebug/issues/98

參考資料:
http://stackoverflow.com/questions/3717136/php-debugging-with-breakpoints-case-studies-examples   PHP Debugging with Breakpoints - case studies, examples..?
http://yansu.org/2014/03/20/php-debug-with-xdebug.html  用Xdebug和Sublime调试PHP代码(主要
https://github.com/martomo/SublimeTextXdebug  SublimeTextXdebug






2016年9月16日 星期五

使用SSH通道翻牆

原本我都是用shadowsocks來走代理的,但是要訪問不對外的網站時,ss的DNS不知道如何設定成機器上的private DNS,設定hosts也無效,最後發現用ssh通道效果出奇的好,只需要設機器上的hosts即可

雖然我電腦是windows,但是cygwin安裝openssh後搭配chrome SwitchySharp依然能使用ssh代理

打開SSH通道
$ ssh -i your.key -D 1234 user@x.x.x.x

然後在瀏覽器上設定代理,如圖



參考資料:
http://www.pchou.info/linux/2015/11/01/ssh-tunnel.html  SSH隧道翻墙的原理和实现



使用nginx限制連線IP

目的
為了只讓VPN連線進來的連線能訪問網站

編輯nginx設定檔
# vim /etc/nginx/sites-available/test.yourdomain.com.conf
在 location / { } 區塊中新增
location / {
    ...
    allow 10.12.0.0/24; # Openconnect / iPhone,你VPN後的IP區段
    deny all;
}
要注意 location ~ \.php$ { }區塊中沒設的話, 訪問php頁面不會受影響

最後重啟nginx


參考資料:
http://www.cyberciti.biz/faq/linux-unix-nginx-access-control-howto/  Nginx Block And Deny IP Address OR Network Subnets


設定Private DNS


有些網址不想讓外面人訪問,所以設定了Private DNS,讓使用VPN連線進來的設備可以直接打開網址訪問私有站。這篇的情況是iPhone 使用AnyConnect 連線openconnect,server系統為 CentOS 7

安裝bind9
# yum install bind bind-utils
編輯 /etc/named.conf 設定檔
# /etc/named.conf
新增 ACL "trusted"區段
acl "trusted" {
        10.12.0.1;    # ns1 - DNS server
        ...
        10.12.0.190;  # iPhone LAN IP
        ...
        10.12.0.254;
};
因為VPN連進來,會自動分配虛擬IP,所以只好窮舉
編輯 options 區段
options {
    listen-on port 53 { 127.0.0.1; 10.12.0.1; };
    # listen-on-v6 port 53 { ::1; };
    ...
    allow-query     { trusted; };  # allows queries from "trusted" clients
    ...
}
10.12.0.1為我連上VPN後的主要DNS IP
在最底下加入
include "/etc/named/named.conf.local";

設定 local file
# vim /etc/named/named.conf.local
zone "test2.yourdomain.com" {
    type master;
    file "/etc/named/zones/db.test2.yourdomain.com";
};
zone "test3.yourdomain.com" {
    type master;
    file "/etc/named/zones/db.test3.yourdomain.com";
};
zone "12.10.in-addr.arpa" {
    type master;
    file "/etc/named/zones/db.10.12";
};

因為我的 test.yourdomain.com DNS解析是設在CloudFlare 公開的,如果這邊zone只設 yourdomain.com ,然後在正解和反解檔案分別設 test2.yourdomain.com 、test3.yourdomain.com,這樣子連vpn後使用私有VPN 雖然查得到 test2.yourdomain.comtest3.yourdomain.com 但設在代管上的test.yourdomain.com會查詢不到

產生Forward Zone File
# chmod 755 /etc/named
# mkdir /etc/named/zones
編輯 test2.yourdomain.com 正解設定
# vim /etc/named/zones/db.test2.yourdomain.com
$TTL    604800
@       IN      SOA     ns1.test2.yourdomain.com. admin.test2.yourdomain.com. (
                  3       ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
; name servers - NS records
     IN      NS      ns1.test2.yourdomain.com.

; name servers - A records
ns1.test2.yourdomain.com.          IN      A       10.12.0.1

; 10.12.0.0/16 - A records
test2.yourdomain.com.        IN      A      10.12.0.1 # 因為我web server和DNS在同一台

編輯 test3.yourdomain.com 正解設定
# vim /etc/named/zones/db.test3.yourdomain.com
$TTL    604800
@       IN      SOA     ns1.test3.yourdomain.com. admin.test3.yourdomain.com. (
                  3       ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
; name servers - NS records
     IN      NS      ns1.test3.yourdomain.com.

; name servers - A records
ns1.test3.yourdomain.com.          IN      A       10.12.0.1

; 10.12.0.0/16 - A records
test3.yourdomain.com.        IN      A      10.12.0.1

編輯反解設定
# vim /etc/named/zones/db.10.12
$TTL    604800
@       IN      SOA     test2.yourdomain.com. test3.yourdomain.com. (
                              3         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
; name servers
      IN      NS      ns1.test2.yourdomain.com.
      IN      NS      ns1.test3.yourdomain.com.

; PTR Records
0.1   IN      PTR     ns1.test2.yourdomain.com.    ; 10.12.0.1
0.1   IN      PTR     ns1.test3.yourdomain.com.    ; 10.12.0.1
0.1   IN      PTR       test2.yourdomain.com.  ; 10.12.0.1

0.1   IN      PTR       test3.yourdomain.com.  ; 10.12.0.1

檢查bind 設定檔語法
# named-checkconf
檢查zone file
# named-checkzone test2.yourdomain.com /etc/named/zones/db.test2.yourdomain.com
zone test2.yourdomain.com/IN: loaded serial 3
OK
這邊 檢查時需特別注意,named-checkzone後的test2.yourdomain.com需換成你正確的域名,否則會報 ignoring out-of-zone data 的警告
# named-checkzone  12.10.in-addr.arpa /etc/named/zones/db.10.12
zone 12.10.in-addr.arpa/IN: loaded serial 3
OK

啟動bind9
# service named start

最後用nslookup檢查是否設定成功
# nslookup
> server 10.12.0.1
Default server: 10.12.0.1
Address: 10.12.0.1#53
> test2.yourdomain.com
Server:         10.12.0.1
Address:        10.12.0.1#53

編輯 /etc/ocserv/ocserv.conf ,讓手機連上VPN後優先選擇內網的DNS
dns = 10.12.0.1
dns = 8.8.8.8
dns = 8.8.4.4
然後重啟oscerv

最後手機連上VPN後訪問 test2.yourdomain.com,成功


參考資料:
https://www.digitalocean.com/community/tutorials/how-to-configure-bind-as-a-private-network-dns-server-on-centos-7  How To Configure BIND as a Private Network DNS Server on CentOS 7
http://blog.ltns.info/linux/openwrt_ocserv_vpn_client_smart_proxy/  OpenWrt路由器搭建和配置ocserv实现VPN客户端智能代理


2016年9月15日 星期四

Letsencrypt 使用心得

前言

想把網站升級到https,避免被gateway的MIS監控
雖然他要看到 https 網站上的內容是可以的,但是如果是要把  client-> server 中間的封包擷取出來分析出內容,以目前技術很難做,他看到的只會是加密的一串不知道什麼東西。除非他用類似 man in the middle attack 的技術,植入一些木馬程式在你的 client 電腦上,讓 client <-> server 中間的加解密失效
但如果是http,那gateway可以看到明文,連cookie也行
所以才說不要隨便亂上一些沒有 https 加密的網站
你如果不信任公司網路的話,一些 http 網站,建議你跳到自己的 server 上

SSH代理

1. Windows 打開 cygwin (需安裝openssh)
# ssh -D 3128 your.server.ip
2. 然後 browser 打開 proxy
底下 localhost 直接連線的設定都要清空,然後在 socket server 那邊填上  127.0.0.1  port 3128,這樣就會透過 ssh tunnel 到你的 server 再連上網站
如圖:
與用shadowsocks方法類似


Letsencrypt 使用限制

Registrations/IP 限制就是每個 IP 只能在 3 小時內發送 10 次請求,如果超過 10 次就會被阻擋,所以申請成功的 Domain,不要隨便砍掉 /etc/letsencrypt/accounts 目錄,否則你就不能重複申請了 => 不是說你的 client -> https server 的連線,是要註冊幾次
Certificates/Domain 限制就是在七天內你的主 Domain 跟 sub Domain 夾起來只能申請五個,所以當你申請五個 domain 時,Letsencrypt 就會阻擋你申請下一個 domain 了,最後要注意的是,Letsencrypt 申請憑證使用期限是 90 天,官方建議如果使用在正式網站,請 60 天重新 renew 一次。

如果某個網站 a.bear.com 沒設dns,直接寫hosts, 這樣還能上http?
這樣也可以上,dns 是 dns

使用lukas2511 的letsencrypt.sh產生證書

Let's Encrypt的腳本不只lukas2511 ,還有其他的。如:
https://github.com/Neilpang/acme.sh
https://github.com/certbot/certbot
這邊以lukas2511 的版本為例
github lukas2511的 letsencrypt.sh 專案後來改名成dehydrated ,需注意
下載最新版本
$ cd ~; git clone https://github.com/lukas2511/letsencrypt.sh.git
$ cd letsencrypt.sh/
把程式安裝到 /etc/letsencrypt.sh/ 下
# mkdir /etc/letsencrypt.sh/
# cp ~/letsencrypt.sh/dehydrated /etc/letsencrypt.sh/
設定config
# echo "WELLKNOWN=/var/www/letsencrypt" > /etc/letsencrypt.sh/config
# mkdir -p /var/www/letsencrypt/
設定/etc/nginx/nginx.conf  ,主要網址 yourdomain.com 設定的server{}中加入
location /.well-known/acme-challenge/ {
    alias /var/www/letsencrypt/;
}
我有把 /var/www/letsencrypt/ 權限改成apache
產生SSL certificate
# /etc/letsencrypt.sh/dehydrated -c -d yourdomain.com
(成功訊息)
# INFO: Using main config file /etc/letsencrypt.sh/config
Processing yourdomain.com
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for yourdomain.com...
 + Responding to challenge for yourdomain.com...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!

成功後產生的檔案都在 /etc/letsencrypt.sh/certs/yourdomain.com/
# ls /etc/letsencrypt.sh/certs/yourdomain.com/ -l
-rw------- 1 root root 1643 Sep 15 03:22 cert-14739097xx.csr
-rw------- 1 root root    0 Sep 15 03:22 cert-14739097xx.pem
-rw------- 1 root root 1643 Sep 15 03:38 cert-14739106xx.csr
-rw------- 1 root root    0 Sep 15 03:38 cert-14739106xx.pem
-rw------- 1 root root 1643 Sep 15 03:49 cert-14739113xx.csr
-rw------- 1 root root    0 Sep 15 03:49 cert-14739113xx.pem
-rw------- 1 root root 1643 Sep 15 03:54 cert-14739116xx.csr
-rw------- 1 root root 2134 Sep 15 03:55 cert-14739116xx.pem
lrwxrwxrwx 1 root root   19 Sep 15 03:55 cert.csr -> cert-14739116xx.csr
lrwxrwxrwx 1 root root   19 Sep 15 03:55 cert.pem -> cert-14739116xx.pem
-rw------- 1 root root 1647 Sep 15 03:55 chain-14739116xx.pem
lrwxrwxrwx 1 root root   20 Sep 15 03:55 chain.pem -> chain-14739116xx.pem
-rw------- 1 root root 3781 Sep 15 03:55 fullchain-14739116xx.pem
lrwxrwxrwx 1 root root   24 Sep 15 03:55 fullchain.pem -> fullchain-14739116xx.pem
-rw------- 1 root root 3243 Sep 15 03:22 privkey-14739097xx.pem
-rw------- 1 root root 3243 Sep 15 03:38 privkey-14739106xx.pem
-rw------- 1 root root 3243 Sep 15 03:49 privkey-14739113xx.pem
-rw------- 1 root root 3243 Sep 15 03:54 privkey-14739116xx.pem
lrwxrwxrwx 1 root root   22 Sep 15 03:55 privkey.pem -> privkey-14739116xx.pem

接著就可以修改 nginx 的 SSL 設定
server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    listen 443 default_server ssl;
    
    # other configs
    ...

    location /.well-known/acme-challenge/ {
        alias /var/www/letsencrypt/;
    }
    ssl_certificate /etc/letsencrypt.sh/certs/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt.sh/certs/yourdomain.com/privkey.pem;
}

listen 443 default_server ssl; 要記得設,不然訪問https 報ERR_CONNECTION_REFUSED 錯誤。
可以檢查443 port有沒有開
# netstat -ant | grep 443
tcp        0      0 0.0.0.0:4433            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN  # 設 listen 後才有
tcp6       0      0 :::4433                 :::*                    LISTEN

重啟nginx
# service nginx restart

配置subdomain 上SSL
server {
    listen  80;
    listen 443 ssl;
    server_name test.yourdomain.com;

    # other configs
    ...

    location /.well-known/acme-challenge/ {
        alias /var/www/letsencrypt/;
    }
    ssl_certificate /etc/letsencrypt.sh/certs/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt.sh/certs/yourdomain.com/privkey.pem;
}
用同一張證書即可

讓不同port的gitlab也掛上SSL
因為我的gitlab走的是不同的port,
在多次修改 /etc/gitlab/gitlab.rb 
external_url 'http://yourdomain.com:1234'
nginx['redirect_http_to_https'] = true
nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
nginx['custom_gitlab_server_config']="location /.well-known/acme-challenge/ {\n alias /var/www/letsencrypt/;\n}\n"
和重啟gitlab後
# gitlab-ctl reconfigure

仍無法實現 https://yourdomain.com:1234 訪問gitlab,但是關閉系統nginx,只啟動gitlab的nginx時可以

讓cron每天自動檢查並更新
設定 /etc/cron.d/letsencrypt-yourdomain_com (因為 /etc/cron.d/ 裡面的檔名不能有 . 這個符號,用 _ 取代)
0 0 * * * root sleep $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400); ( /etc/letsencrypt.sh/dehydrated -c -d yourdomain.com; /sbin/service nginx reload ) > /tmp/dehydrated-yourdomain.com.log 2>&1
在cron job 中 $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400) 
設計是利用機器名稱產生出十六進位 hash 值,抓一部分轉成十進位後除以一天的秒數,得到餘數後先停這個秒數再跑 dehydrated ,這樣可以避免同時間有太多機器到 Let's Encrypt 的伺服器,造成類似 DDoS 的攻擊。

使用wireshark 查封包
選擇網卡後篩選出傳到自己主機的封包
HTTP:
http && ip.addr == x.x.x.x
HTTPS:
ssl && ip.addr == x.x.x.x
刷網頁時記得用ctrl+f5清緩存,否則封包304緩存去看是不準確的
可以發現 ssl 的封包被加密過,http的封包可以看到明文(HTML)
Linux可以用tcpdump

參考資料:
Rellik
https://letsencrypt.tw/   (主要)
https://github.com/lukas2511/dehydrated (主要)
https://blog.wu-boy.com/2015/12/letsencrypt-entering-public-beta-free-ssl/  Letsencrypt 開放申請免費 SSL 憑證
https://www.digitalocean.com/community/tutorials/how-to-create-an-ssl-certificate-on-nginx-for-ubuntu-14-04  How To Create an SSL Certificate on Nginx for Ubuntu 14.04
https://www.foolegg.com/how-to-secure-your-websites-with-lets-encrypt-certificate/  [教學] 如何使用 Let’s Encrypt 加密網站的連線
http://stackoverflow.com/questions/34189199/how-do-i-use-let-s-encrypt-with-gitlab  How do I use let’s encrypt with gitlab?
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md  NGINX settings
https://www.digitalocean.com/community/tutorials/how-to-secure-gitlab-with-let-s-encrypt-on-ubuntu-16-04  How To Secure GitLab with Let's Encrypt on Ubuntu 16.04