https://www.ibm.com/quantum-computing/
Ibm_xxxxxxxxではログインできなかったので、googleのアカウントでログイン






うん、多分作れているんだろう。000」と「011」が約50%で発生している(上位ビットは無視して良い思う)から。1024回くらい繰返しているみたい。ただ、(当然だけど)量子の非局所化を確認する方法って、ないんだろうなぁ
江端智一のホームページ
https://www.ibm.com/quantum-computing/
Ibm_xxxxxxxxではログインできなかったので、googleのアカウントでログイン
うん、多分作れているんだろう。000」と「011」が約50%で発生している(上位ビットは無視して良い思う)から。1024回くらい繰返しているみたい。ただ、(当然だけど)量子の非局所化を確認する方法って、ないんだろうなぁ
Access to XMLHttpRequest at 'http://localhost:8080/api/loc/2' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
test.html:30 GET http://localhost:8080/api/loc/2 net::ERR_FAILED
が取れなくて困っていたので、以下のアドインを入れて強制的に解決した(デフォルトで、"なんでもOK")としておけばよさそう)。
ちなみに、これを使うと、Twitterで通信障害「"問題が発生しました" "やりなおす"」が発生するようなので、実験が終ったら、解除しておいた方が良いです。
ちなみに、上記の問題はjavascriptで発生している問題ですが、Go連携でなんとかしようかと思っていたところで、Sさんから、以下の情報を頂きました。
多分、今日あたりからぶつかりそうな問題でした。
で、今ぶつかっている問題ですが、JSON.parseから、情報が取れないんですよね。なんでかなー、色々試しているんだけど、もう疲れてきたなぁ。VSCでデバッグしているんですけど、dataの中身がスカスカなんですよねー。うん困った。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0.1//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" Content="text/html;charset=Shift_JIS">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>同期通信テスト</title>
<script>
// (1)XMLHttpRequestオブジェクトを作成
var xmlHttp = new XMLHttpRequest();
// (2)onreadystatechangeイベントで処理の状況変化を監視
//xmlHttp.onreadystatechange = function(){
// if(this.readyState == 4 && this.status == 200){
// //console.log(this.responseText);
// data = this.response
// }
//}
//var data;
// (3)HTTPのGETメソッドとアクセスする場所を指定
xmlHttp.open("GET", "http://localhost:8080/api/loc/2", true);
//xmlHttp.onload = function(){
// if (xmlHttp.status >= 200 && xmlHttp.status < 200){
// data = JSON.parse(xmlHttp.responseText);
// } else {
// console.log("error");
// }
//}
//xmlHttp.responseType = 'json'
// (4)HTTPリクエストを送信
xmlHttp.send();
var data = JSON.parse(xmlHttp.responseText);
//alert(xmlHttp.responseText);
console.log(xmlHttp.response);
console.log(xmlHttp.responseText);
JSON.parse(data.responseText);
//console.log(data);
//var user = JSON.parse(this.responseText);
//var user = JSON.parse(data);
//var user = JSON.parse(this.responseText);
//alert(user);
</script>
https://www.prakharsrivastav.com/posts/from-http-to-https-using-go/ が原典
Goを使ってHTTPからHTTPSへ
2019-08-02 :: プラカール・スリバスタフ
序章
この記事では、Go で TLS 暗号化を設定する方法を学びます。さらに、相互にTLS暗号化を設定する方法を探っていきます。このブログ記事で紹介されているコードはこちらからご覧いただけます。この記事では、関連するスニペットを表示しています。興味のある読者は、リポジトリをクローンしてそれに従ってください。
まず、シンプルな Http サーバとクライアントを Go で書くことから始めます。次に、サーバで TLS を設定することで、両者間のトラフィックを暗号化します。この記事の最後に、両者間の相互 TLS を設定します。
シンプルなhttpサーバー
まず、Go で Http クライアント・サーバの実装を作成してみましょう。localhost:8080 に到達可能な Http エンドポイント /server を公開します。そして、http.Clientを使ってエンドポイントを呼び出し、その結果を表示します。
完全な実装はこちらを参照してください。
// Server code
mux := http.NewServeMux()
mux.HandleFunc("/server", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Protect Me...")
})
log.Fatal(http.ListenAndServe(":8080", mux))
// Client code
if r, err = http.NewRequest(http.MethodGet, "http://localhost:8080/server", nil); err != nil {
log.Fatalf("request failed : %v", err)
}
c := http.Client{
Timeout: time.Second * 5,
Transport: &http.Transport{IdleConnTimeout: 10 * time.Second},
}
if data, err = callServer(c, r); err != nil {
log.Fatal(err)
}
log.Println(data) // Should print "Protect Me..."
次のセクションでは、TLS を使用してクライアントとサーバ間のトラフィックを暗号化します。その前に、公開鍵インフラストラクチャ (PKI) をセットアップする必要があります。
PKI のセットアップ
ミニ PKI インフラストラクチャをセットアップするために、minica という Go ユーティリティを使用して、ルート、サーバ、クライアントの鍵ペアと証明書を作成します。実際には、認証局 (CA) またはドメイン管理者 (組織内) が鍵ペアと署名付き証明書を提供してくれます。私たちの場合は、minicaを使ってこれをプロビジョニングしてもらうことにします。
鍵ペアと証明書の生成
注: これらを生成するのが面倒に思える場合は、Github リポジトリでコミットされた証明書を再利用することができます。
以下の手順で証明書を生成します。
minicaをインストールする: github.com/jsha/minicaを取得してください。
minica --domains server-certを実行してサーバ証明書を作成します。
初めて実行すると4つのファイルが生成されます。
minica.pem(ルート証明書
minica-key.pem (root 用の秘密鍵)
server-cert/cert.pem (ドメイン「server-cert」の証明書、ルートの公開鍵で署名されています)
server-cert/key.pem (ドメイン「server-cert」の秘密鍵)
minica --domains client-certを実行してクライアント証明書を作成します。2つの新しいファイルが生成されます。
client-cert/cert.pem (ドメイン "client-cert "の証明書)
client-cert/key.pem (ドメイン "client-cert "の秘密鍵)
また、minicaでドメインの代わりにIPを使用して鍵ペアや証明書を生成することもできます。
etc/hosts にエイリアスを設定する
上記で生成したクライアント証明書とサーバ証明書は、それぞれドメイン server-cert と client-cert で有効です。これらのドメインは存在しないので、localhost(127.0.0.1)のエイリアスを作成します。これを設定すると、localhost の代わりに server-cert を使用して Http サーバにアクセスできるようになります。
Linux以外のプラットフォームを使っている場合は、OSに合わせた設定方法をググってみてください。私はLinuxマシンを使っていますが、ドメインエイリアスの設定はとても簡単です。etc/hostsファイルを開き、以下の項目を追加します。
127.0.0.1 server-cert
127.0.0.1 client-cert
この時点で、インフラストラクチャの設定は完了です。次のセクションでは、クライアントとサーバ間のトラフィックを暗号化するために、これらの証明書を使ってサーバを設定します。
サーバーでTLSを設定する
サーバ-certドメインに生成された鍵と証明書を使って、サーバにTLSを設定してみましょう。クライアントは先ほどと同じです。唯一の違いは、3つの異なるURLでサーバを呼び出すことで、何が起こっているのかを理解することです。
完全な実装はこちら
// Server configuration
mux := http.NewServeMux()
mux.HandleFunc("/server", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "i am protected")
})
log.Println("starting server")
// Here we use ListenAndServerTLS() instead of ListenAndServe()
// CertPath and KeyPath are location for certificate and key for server-cer
log.Fatal(http.ListenAndServeTLS(":8080", CertPath, KeyPath, mux))
// Server configuration
c := http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{IdleConnTimeout: 10 * time.Second,},
}
if r, err = http.NewRequest(http.MethodGet, "http://localhost:8080/server", nil); err != nil { // 1
//if r, err = http.NewRequest(http.MethodGet, "https://localhost:8080/server", nil); err != nil { // 2
//if r, err = http.NewRequest(http.MethodGet, "https://server-cert:8080/server", nil); err != nil { // 3
log.Fatalf("request failed : %v", err)
}
if data, err = callServer(c, r); err != nil {
log.Fatal(err)
}
log.Println(data)
http.ListenAndServeTLS()を使用してサーバを起動します。これにはポート、公開証明書へのパス、秘密鍵へのパス、そしてHttp-handlerの4つの引数が必要です。サーバからのレスポンスを見てみましょう。私たちは失敗しますが、私たちはどのようにHttp暗号化が動作するかについてのより多くの洞察を与える3つの異なる要求を送信します。
Attepmt 1 http://localhost:8080/server に送信すると、応答があります。
Client Error. Get http://localhost:8080/server: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03x01x00x02\x02"
サーバエラー: http: 127.0.0.1:35694 からの TLS ハンドシェイクエラー: tls: 最初のレコードが TLS ハンドシェイクのように見えません。
これは、サーバーが暗号化されたデータを送信していることを意味する良いニュースです。Http経由では誰も意味をなさないでしょう。
Attempt 2 to https://localhost:8080/server、レスポンスは以下の通りです。
クライアントエラーです。Get https://localhost:8080/server: x509: certificate is valid for server-cert, not localhost
サーバエラー: http: 127.0.0.1:35698 からの TLS ハンドシェイクエラー: リモートエラー: tls: 不正な証明書
これはまたしても朗報です。これは、ドメインサーバ証明書に発行された証明書を他のドメイン(ローカルホスト)で使用することができないことを意味します。
Attempt 3 to https://server-cert:8080/server、応答があります。
クライアントエラーです。Get https://server-cert:8080/server: x509: certificate signed by unknown authority
サーバエラー: http: 127.0.0.1:35700 からの TLS ハンドシェイクエラー: リモートエラー: tls: 不正な証明書
このエラーは、クライアントがその証明書に署名したことを信頼していないことを示しています。クライアントは証明書に署名した CA を認識していなければなりません。
このセクションの全体的な考えは、TLS が保証する 3 つの保証を実証することでした。
メッセージは常に暗号化されている。
サーバが実際に言っている通りのものであること。
クライアントはサーバの証明書を盲目的に信じてはいけない。クライアントは、CA を通じてサーバの身元を確認できるようにしなければなりません。
クライアントでCA証明書を設定する
クライアント側のCA証明書を設定して、ルートCAの証明書とサーバの身元を照合できるようにします。サーバ証明書はルートCAの公開鍵を使って署名されているので、TLSハンドシェイクが有効になり、通信が暗号化されます。
完全な実装はこちらにあります。
// create a Certificate pool to hold one or more CA certificates
rootCAPool := x509.NewCertPool()
// read minica certificate (which is CA in our case) and add to the Certificate Pool
rootCA, err := ioutil.ReadFile(RootCertificatePath)
if err != nil {
log.Fatalf("reading cert failed : %v", err)
}
rootCAPool.AppendCertsFromPEM(rootCA)
log.Println("RootCA loaded")
// in the http client configuration, add TLS configuration and add the RootCAs
c := http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
IdleConnTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{RootCAs: rootCAPool},
},
}
if r, err = http.NewRequest(http.MethodGet, "https://server-cert:8080/server", nil); err != nil {
log.Fatalf("request failed : %v", err)
}
if data, err = callServer(c, r); err != nil {
log.Fatal(err)
}
log.Println(data)
// server response
prakhar@tardis (master)? % go run client.go
RootCA loaded
i am protected # response from server
これにより、先ほど説明した3つの保証がすべて保証されます。
相互TLSの設定
サーバーにクライアントの信頼を確立しています。しかし、多くのユースケースでは、サーバーがクライアントを信頼する必要があります。例えば、金融、医療、公共サービス業界などです。これらのシナリオのために、クライアントとサーバーの間で相互にTLSを設定して、双方がお互いを信頼できるようにします。
TLSプロトコルは、最初からこれをサポートしています。相互TLS認証を設定するために必要な手順は以下の通りです。
1.サーバはCA(CA-1)から証明書を取得します。クライアントは、サーバの証明書に署名したCA-1の公開証明書を持っている必要があります。
2.クライアントは CA (CA-2) から証明書を取得します。サーバは、クライアントの証明書に署名したCA-2の公開証明書を持っていなければなりません。簡単にするために、クライアント証明書とサーバ証明書の両方に署名するために同じ CA (CA-1 == CA-2) を使用します。
3.サーバは、すべてのクライアントを検証するためにCA証明書プールを作成します。この時点で、サーバはCA-2の公開証明書を含む。
4.同様に、クライアントは独自のCA証明書プールを作成し、CA-1の公開証明書を含む。
5.両者は、CA 証明書プールに対して受信要求を検証します。どちらか一方に検証エラーがあった場合、接続は中断されます。
実際に動作を見てみましょう。この機能の完全な実装はこちらを参照してください。
サーバーの設定
mux := http.NewServeMux()
mux.HandleFunc("/server", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "i am protected")
})
clientCA, err := ioutil.ReadFile(RootCertificatePath)
if err != nil {
log.Fatalf("reading cert failed : %v", err)
}
clientCAPool := x509.NewCertPool()
clientCAPool.AppendCertsFromPEM(clientCA)
log.Println("ClientCA loaded")
s := &http.Server{
Handler: mux,
Addr: ":8080",
TLSConfig: &tls.Config{
ClientCAs: clientCAPool,
ClientAuth: tls.RequireAndVerifyClientCert,
GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, e error) {
c, err := tls.LoadX509KeyPair(CertPath, KeyPath)
if err != nil {
fmt.Printf("Error loading key pair: %v\n", err)
return nil, err
}
return &c, nil
},
},
}
log.Fatal(s.ListenAndServeTLS("", ""))
この設定で注意すべき点がいくつかあります。
クライアント設定
http.Clientの設定は、クライアントの設定も少し変わります。
rootCA, err := ioutil.ReadFile(RootCertificatePath)
if err != nil {
log.Fatalf("reading cert failed : %v", err)
}
rootCAPool := x509.NewCertPool()
rootCAPool.AppendCertsFromPEM(rootCA)
log.Println("RootCA loaded")
c := http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
IdleConnTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{
RootCAs: rootCAPool,
GetClientCertificate: func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
c, err := tls.LoadX509KeyPair(ClientCertPath, ClientKeyPath)
if err != nil {
fmt.Printf("Error loading key pair: %v\n", err)
return nil, err
}
return &c, nil
},
},
},
}
サーバと比較した場合の設定の違いに注目してください。
クライアントとサーバの相互TLS認証の実行
# Server logs
2019/08/01 20:00:50 starting server
2019/08/01 20:00:50 ClientCA loaded
2019/08/01 20:01:01 client requested certificate
Verified certificate chain from peer:
Cert 0:
Subject [client-cert] # Server shows the client certificate details
Usage [1 2]
Issued by minica root ca 5b4bc5
Issued by
Cert 1:
Self-signed certificate minica root ca 5b4bc5
# Client logs
2019/08/01 20:01:01 RootCA loaded
Verified certificate chain from peer:
Cert 0:
Subject [server-cert] # Client knows the server certificate details
Usage [1 2]
Issued by minica root ca 5b4bc5
Issued by
Cert 1:
Self-signed certificate minica root ca 5b4bc5
2019/08/01 20:01:01 request from server
2019/08/01 20:01:01 i am protected
結論
TLS の設定は、実装の問題というよりも証明書の管理の問題が常にあります。TLS 設定における典型的な混乱は、実装というよりも正しい証明書の使用に関連していることが多いです。TLS プロトコルとハンドシェイクを正しく理解していれば、Go は箱から出してすぐに必要なものをすべて提供してくれます。
また、理論的な観点からTLSの暗号化とセキュリティを探求した以前の記事もチェックしてみてください。
参考文献
この記事は、Gophercon-2018でのLiz Riceの素晴らしいトークに大きく影響されていますので、ぜひチェックしてみてください。その他の参考文献は以下の通りです。
secure-connections: gophercon のためのレポ
minica 認証局
Eric Chiangによるこの驚くべき記事。必読です。
step-by-step-guide-to-mtls-in-go.
mediumのこの記事。
サーバ側 loc_rest_server.go というファイル名で保存して、
>go run loc_rest_server.go
で起動
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/mux"
)
/*
type GetLoc struct {
Message string `json:"message"`
Name string `json:"name"`
}
*/
/*
// GetLoc GetLoc
type GetLoc struct {
ID int64 `json:"id"`
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
//Address string `json:"address"`
}
*/
// GetLoc GetLoc
type GetLoc struct {
ID string `json:"id"`
Lat string `json:"lat"`
Lng string `json:"lng"`
//Address string `json:"address"`
}
// ErrorResponse error response
type ErrorResponse struct {
Code int `json:"code"`
Message string `json:"message"`
}
// locService loc service
func locService(ctx context.Context, number string, tm time.Time) (*GetLoc, error) {
if number == "1" {
return &GetLoc{
ID: number,
Lat: "35.653976",
Lng: "139.796842",
}, nil
}
if number == "2" {
return &GetLoc{
ID: number,
Lat: "35.653758",
Lng: "139.794192",
}, nil
}
return nil, nil
}
// AppHandler application handler adaptor
type AppHandler struct {
h func(http.ResponseWriter, *http.Request) (int, interface{}, error)
}
func (a AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
encoder := json.NewEncoder(w)
status, res, err := a.h(w, r)
if err != nil {
log.Printf("error: %s", err)
w.WriteHeader(status)
encoder.Encode(res)
return
}
w.WriteHeader(status)
encoder.Encode(res)
return
}
/*
// GetLoc GetLoc
func (app *App) GetLoc(w http.ResponseWriter, r *http.Request) (int, interface{}, error) {
res, err := locService(r.Context(), "", time.Now())
if err != nil {
app.Logger.Printf("error: %s", err)
e := ErrorResponse{
Code: http.StatusInternalServerError,
Message: "something went wrong",
}
return http.StatusInternalServerError, e, err
}
app.Logger.Printf("ok: %v", res)
return http.StatusOK, res, nil
}
*/
// GetLocWithNumber GetLoc with number
func (app *App) GetLocWithNumber(w http.ResponseWriter, r *http.Request) (int, interface{}, error) {
val := mux.Vars(r)
//res, err := locService(r.Context(), val["id"], time.Now())
res, err := locService(r.Context(), val["id"], time.Now())
if err != nil {
app.Logger.Printf("error: %s", err)
e := ErrorResponse{
Code: http.StatusInternalServerError,
Message: "something went wrong",
}
return http.StatusInternalServerError, e, err
}
app.Logger.Printf("ok: %v", res)
return http.StatusOK, res, nil
}
// App application
type App struct {
Host string
Name string
Logger *log.Logger
}
func main() {
host, err := os.Hostname()
if err != nil {
log.Fatal(err)
}
app := App{
Name: "my-service",
Host: host,
Logger: log.New(os.Stdout, fmt.Sprintf("[host=%s] ", host), log.LstdFlags),
}
// for gorilla/mux
router := mux.NewRouter()
r := router.PathPrefix("/api").Subrouter()
//r.Methods("GET").Path("/loc").Handler(AppHandler{h: app.GetLoc})
//r.Methods("GET").Path("/loc/staticName").Handler(AppHandler{h: app.GetLoc})
r.Methods("GET").Path("/loc/{id}").Handler(AppHandler{h: app.GetLocWithNumber})
if err := http.ListenAndServe(":8080", router); err != nil {
log.Fatal(err)
}
}
クライアント側
main.go で保存して、
>go run main.go
で起動
参考とさせて頂いたページ「Goでhttpリクエストを送信する方法」
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
//url := "http://google.co.jp"
url := "http://localhost:8080/api/loc/2"
resp, _ := http.Get(url)
defer resp.Body.Close()
byteArray, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(byteArray)) // htmlをstringで取得
}
動作結果
>go run main.go
{"id":"2","lat":"35.653758","lng":"139.794192"}
JSONで展開するにはどうしたらいいかな?
参考にさせて頂いたのは「goでjson apiを叩く」
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
// GetLoc GetLoc
type GetLoc struct {
ID string `json:"id"`
Lat string `json:"lat"`
Lng string `json:"lng"`
//Address string `json:"address"`
}
func main() {
//url := "http://google.co.jp"
url := "http://localhost:8080/api/loc/2"
resp, _ := http.Get(url)
defer resp.Body.Close()
/*
byteArray, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(byteArray)) // htmlをstringで取得
*/
var d GetLoc
fmt.Printf("======Body (use json.Unmarshal)======\n")
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(body, &d)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%v\n", d)
fmt.Printf("ID:%v\n", d.ID)
fmt.Printf("Lat:%v\n", d.Lat)
fmt.Printf("Lng:%v\n", d.Lng)
}
出力結果
>go run main.go
======Body (use json.Unmarshal)======
{2 35.653758 139.794192}
ID:2
Lat:35.653758
Lng:139.794192
WiMAX 2+ は、有線(USB)で使えないと思っていたけど、USBで表示されたドライブ(D:)をクリックしたら使えるようになった。本体の方で特別な設定はしなかった。とりあえずメモで。
私が今使っているWordPressは、現時点での最新バージョンなのですが、どうしても、Prism For WPのメニューが出てこなくて、ずっと悩んでいました。
で、色々しらべた結果、
をインストールする必要があるらしく、これを入れることでメニューがでるようになりました。
が今度は、画像イメージのコピペができなくなりました。
で、さらに、
をインストールして、この画面のようにコピペを張りつけるように戻すことができるようになりました。
なんか、やりたいことを実現していくと、どんどんWordPressのダウングレードをしているような気になってきました(プラグインもどんどん入れることになって、気持ち悪いです(経験上、プラグインの入れすぎは、トラブルの元になります))。
常日頃から御指導頂いているSさんから、Bad Elf 2300の位置情報をキャプチャするhtmlファイルの内容を教えて頂いた。忘れないように、残しておく。
Bad ElfをBTでリンクしたiPadで稼働を確認済み(iPhoneでは稼働確認できなかった)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>geolocation-sample</title>
</head>
<body>
<div id="output"></div>
<script>
var output = document.getElementById('output');
// 位置情報の取得に成功した際のコールバック
const successCallback = (position) => {
console.log(position);
output.innerHTML += "<P>==========";
output.innerHTML += "<P>time:" + position.timestamp;
output.innerHTML += "<P>latitude:" + position.coords.latitude;
output.innerHTML += "<P>longitude:" + position.coords.longitude;
output.innerHTML += "<P>altitude:" + position.coords.altitude;
output.innerHTML += "<P>accuracy:" + position.coords.accuracy;
output.innerHTML += "<P>altitudeAccuracy:" + position.coords.altitudeAccuracy;
output.innerHTML += "<P>heading:" + position.coords.heading;
output.innerHTML += "<P>speed:" + position.coords.speeed;
};
// 位置情報の取得に失敗した際のコールバック
const errorCallback = (err) => {
console.log(err);
output.innerHTML += "Error\n";
};
// 位置を監視する構成オプション
// オプションの内容は次のリンクに書かれています。
// https://developer.mozilla.org/ja/docs/Web/API/PositionOptions
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
let watchPositionID;
window.onload = () => {
// navigator.geolocation.watchPositionについては次のURLにかかれています。
// https://developer.mozilla.org/ja/docs/Web/API/Geolocation/watchPosition
watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
};
// ブラウザーを閉じる前に位置の監視を止めます
window.onbeforeunload = () => {
navigator.geolocation.clearWatch(watchPositionID);
}
</script>
</body>
</html>
ChromウェブストアのMarkdown Preview Plusのページを開きます
https://chrome.google.com/webstore/detail/markdown-preview-plus/febilkbfcbhebfnokafefeacimjdckgl?hl=ja
[Chromeに追加]ボタンをクリックします
から、
から「詳細」を選び
をアクティブにするのが重要。
なかなか便利です。
以上
ここのところ、Websocket通信のセキュア化のコーディングで、かなり嵌ってしまっている私に、師匠のSさんから、
GoのサーバーでWSSやHTTPSのプロトコルを直接扱うことをせず、かわりに、リバースプロキシサーバーでHTTPSやWSSプロトコルを扱い、GoのサーバーではHTTPやWSプロトコルを扱うように構成を変更する、というのはいかがでしょうか?
とのご提言を頂きました。
あ、そりゃそうだ ―― と思いました。私は、Websocket通信のアタックさえ回避できれば、なんでも良いわけでして、何がなんでもwssをやりたい訳ではありません。
インターネットの中でセキュアが担保できれば、内部システムなんぞスカスカでも構いません(そもそも、システム内部に侵入されたら、その時点で"システムとしては、"The END"です)。
とりあえずPC(Windows10 Box)の中でnginx(Webサーバ)を立てようと思いました。
いや、驚くほど簡単。「インストールから実行まで10秒を切ったWebサーバ」というのは生まれて始めてかもしれません。
http://nginx.org/en/download.html から、Stable versionをダウンロードして、
解凍して、"nginx.exe"を叩くだけ。(私の場合、ダウンロードの場所は、C:\の直下にしておきました)
これで、ブラウザから、http://localhost と入力して稼動確認
ちなみに、トップページは、htmlフォルダの中にあるので、適当に変更すれば、普通のWebサーバにもなります。
それはさておき。
今回の場合、クライアントからnginxまでのセキュアが確保できれば足り、その後ろは、普通のwebsocketの通信ができれば良い、とします(golangでwebsocketのセキュア通信って、もう気が狂いそうになるほど面倒)。
Sさんからは、nginx.confを送付して貰ったのですが、まあ、当然ですが、一発では動きませんでしたので、先ず、セキュア通信なしのリバースプロキシを動かしてみます。
nginxでポート8000で受けて、それを、エコーサーバ(8080)に転送するだけのものですが、NginxのリバースプロキシでWebソケットを通す際の設定 とSさんから送って頂いた設定ファイルを参考にさせて頂いて、以下のようにconf/nginx.confの内容を書き換えました。
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8000;
server_name localhost;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_read_timeout 86400;
}
}
}
ちなみにエコーサーバは、以下のものをそのまま使っています。
でもって、こんな感じでちゃんと動いています。もちろんlocalhost:8080でも動きます。
ーーーー
では、ここから、ngnixまでのセキュア化の検討を開始します。
ここでしばしスタック中。TLSがちゃんと動いているのか不安になったので、普通のWebでできるか、以下のようなnginx.confを使って、index.htmlで試してみました。
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate algo.crt; # https://wp.kobore.net/2020/09/post-1124/で作ったもの
ssl_certificate_key algo.key; # 同上
location / {
root html;
index index.html index.htm;
}
}
}
https://localhost/ でも、http://localhost/ でも動いていますので、algo.crt, algo.keyについては(多分)大丈夫だと思われます。
では、元の問題に戻りましょう。(4時間格闘)
どうやら、外向けをセキュアにするには、nginx.confを3箇所だけ変更追加すれば良い、と記載されていたので、以下のようなnginx.confに改造した "#change"と、"#add"のところだけ。
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
#listen 8000;
listen 443 ssl; # change
server_name localhost;
ssl_certificate algo.crt; #add
ssl_certificate_key algo.key; #add
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_read_timeout 86400;
}
}
}
ところが、https://localhost を実施しても、サーバ側から、以下のエラーがでてきて、どうにもならない。
upgrade:websocket: the client is not using the websocket protocol: 'websocket' token not found in 'Upgrade' header
Visual Studio Codeにかけて、サーバでトレースしても読めないし(htmlの部分だから無理ない)、正直もうどうして良いか分からなくなってきたとき、「あ、chromoのディベロッパーツールを使えばいいか」と気が付きました。
そんでもって、
これで気がつきました。ここって"ws:"ではなくて、"wss:"にしないとアカンのじゃないかな、と。
で、ここを修正して、ECHOサーバを立ち上げ直したら、無事稼動することが確認できました。
まあ、まだまだ課題山積ですが、とりあえず、家(システム)の外はセキュアにする目処が立ちましたので、wssの通信プログラムで苦労するのは「やめる方向」で決定しました。
nginxをリバースプロキシにして、そこまではガチガチにしておき、家の中はユルユルに作るで、進めていくことにします。
以上