UP | HOME

好好学习,天天向上

Table of Contents

Flash crossdomain.xml 跨站请求伪造漏洞   @original

Flash crossdomain.xml 跨站请求伪造漏洞是指黑客利用Flash跨域配置文件(crossdomain.xml)的配置缺陷进行的跨域攻击。
如果网站根目录下有crossdomain.xml文件且这个xml文件的allow-access-from标签为通配符*,那么任意域就可以跨域获取本域的隐私数据。
这个漏洞易被攻击者利用,会导致网站Cookie信息被窃取,威胁网站用户安全。
2015年06月 7日  1:34 Sun AM by josephzeng push

项目管理步骤   @original

1. 确定项目背景
项目背景,主要目标
产品,需求提出者,项目管理,开发,测试,运维
《干系人表》

2. 组织需求会议(评审,确定产出和时间点)
需求评审
确定产出
确定时间点
《需求文档》

3. 制定设计方案
《方案设计》
《外部接口文档》
《测试用例》

4. 项目迭代计划
《项目计划表》
确定优先级

5. 执行项目计划
《项目日报》
《项目周报》

6. 项目总结
《项目总结文档》
项目总结会议

7. 风险管控
确定主要风险
制定控制风险的计划,例如使用迭代减少需求风险,例如预留预研时间或B计划的时间
确定各个步骤的资源到位情况,如有必要调整方案和计划

2015年06月 9日  3:14 二 下午 by josephzeng push @original

安全整改建议   @original

1 前言
增强安全编码意识,加强安全上线规范,提高服务器环境安全要求,减少线上漏洞的发生。

2 建议
2.1 运维方面
2.1.1 发布系统
增强发布系统代码检测(根据开发语言或自定义限制非法文件提交,如.bak,.20150505等等)
发现问题一律不给发布。
备注:
1. 开发整理所有线上项目需要支持的文件格式
2. 发布系统开发增加代码检测功能
2.1.2 Nginx配置
新项目上线,nginx可以按照开发要求配置conf,定义或限制一些文件类型或目录的访问限制
备注:
1. O提单安装软件的时候,注明Nginx默认配置按严格环境走
如:php应用服务nginx只支持php, nginx, js,css,html
2.1.3 Php配置
新项目上线,php配置,必须强制要求过滤一些危险函数
备注:
1. O提单安装软件的时候,注明已经屏蔽过滤了这些高危函数
2. 需要过滤屏蔽的高危函数列表

2.1.4 Mysql数据库
所有项目数据库账号密码最小权限申请使用
备注:
1. DBA负责开发数据库管理系统?

2.1.5 培训分享
安全测试小组定期安全培训及一些扫描工具分享给开发,提高自测能力和意识

备注:
由运维安排,每个月必须有一次

2.2 开发方面
2.2.1 框架
2.2.1.1 新项目 php框架目录
新项目 php框架目录设计重新设计为
    ├── xxx
	├── coxx
	├── xxx
	├── xxx
	└── web web 根目录
   并纠正为一台机器只有一个coxx,所有应用自己的coxx都属于继承公共的coxx,方便自定义业务需求
备注:
1. 框架整改
整改点:COXX, 跟目录和日志目录配置

2.2.1.2 新项目 web 根目录设置为应用程序根目录的web目录

2.2.2 编码规范及安全
2.2.2.1 重新梳理编码规范,持续修正编码规范,邮件或OA公布
   编码规范列表
   前端编码规范(html,css,js)
   php编码规范
   python编码规范
   golang编码规范
   java编码规范
   c++编码规范
   lua编码规范
   等等
2.2.2.2 坚持code review(每个小组一个礼拜至少安排一次)   
2.2.2.3 月统计被发现的漏洞情况及总结原因,邮件或OA公布
   安全相关人员出安全月总结报告
2.2.2.4 新增常见防范漏洞方法提醒推送
   安全相关人员负责收集提醒(公司所有人可以发送给安全相关人员负责纪录收集)推送给开发人员

2.2.3 流程规范
2.2.3.1 开发测试上线一定需遵守公司流程
开发->自测->测试小组->安全扫描(或安全小组测试,或外部安全测试)->发布系统->预发布->线上
2.2.4 新员工
熟悉编码规范
跟进新员工的编码规范情况及开发测试上线的流程遵守情况(导师或指定相关人员)

2015年06月 9日  3:15 二 下午 by josephzeng push @original

rabbitmq使用备注   @original

容易疏忽的坑点:
rabbitmq日志最好设置到硬盘充足的目录
RABBITMQ_LOG_BASE=/data1/var/log/rabbitmq
RABBITMQ_MNESIA_BASE=/data1/var/lib/rabbitmq/mnesia

启动:
./sbin/rabbitmq-server –detached &

添加账号:
rabbitmqctl add_user user  passwd
rabbitmqctl set_user_tags user administrator
rabbitmqctl set_permissions -p /  user '.*' '.*' '.*'

安装脚本:
#!/bin/bash

yum -y install gcc glibc-devel make ncurses-devel openssl-devel autoconf gcc-c++ git libxslt

cd /usr/local/src/
wget http://url/src/jdk-7u55-linux-x64.rpm
rpm -i jdk-7u55-linux-x64.rpm
wget http://url/src/otp_src_R15B01.tar.gz
tar zxf otp_src_R15B01.tar.gz
cd otp_src_R15B01
./configure
make && make install
cd ..

2015年06月 9日  4:46 二 下午 by josephzeng push

canal to rabbitmq   @original

最近为了业务层避免直接使用mysql,可以自定义使用缓存层(如:redis等等)同时又可以获取到后台管理更新的数据(mysql)
我们设计了利用canal订阅mysql更新的数据,并将数据发布到rabbitmq队列,由业务层去选择使用缓技术消费rmq数据。

架构简图(有空再补详细架构图)
+---------+       +-------+       +--------------+
| 后台管理 |  <--> | mysql |  -->  | canal server |
+---------+       +-------+       +--------------+

+--------------+      +----------+       +----------+     +-------+
| canal client | -->  | rabbitmq |  ---> | todo...1 | --> | redis |
+--------------+      +----------+       +----------+     +-------+
                               |         +----------+     +-----------+
                               |-------> | todo...2 | --> | memcached |                
                               |         +----------+     +-----------+ 
                               |         +----------+     +---+
                               --------> | todo...n | --> | ? | 
                                         +----------+     +---+

代码片段:
/**
 * mysql data handler
 * @author josephzeng
 *
 */
public class MysqlHandler {

    /**
     * 
     */
    static Logger log4j = Logger.getLogger(MysqlHandler.class.getClass());

    /**
     * get resource config
     */
    private static ResourceBundle resourceBundle;

    /**
     * init 
     * @param myResourceBundle
     */
    public MysqlHandler(ResourceBundle myResourceBundle) {
        resourceBundle = myResourceBundle;
    }

    /**
     * get redis config mysql database name
     */
    private static String getMysqlDatabaseName(){
        String databaseName = null;
        try{
            SAXReader reader = new SAXReader();  
            Document document = null;
            String fileName = resourceBundle.getString("synredis_config");   
            document = reader.read(fileName);
            Element rootElm = document.getRootElement();
            databaseName = rootElm.element("database").getTextTrim().toString();
        } catch (Exception e) {
            log4j.error(e.getMessage());
        }
        return databaseName;
    }   

    private static Map<String,String> getMysqlTableFields(){
        Map<String,String> tableFields = new HashMap<String, String>();
        try{
            SAXReader reader = new SAXReader();  
            Document document = null;
            String fileName = resourceBundle.getString("synredis_config");   
            document = reader.read(fileName);
            Element rootElm = document.getRootElement();
            String databaseName = rootElm.element("database").getTextTrim().toString();

            List<Node> list = (List<Node>)document.selectNodes("//synredis/table_data/row");
            for(Node n : list) {  
                Element messagesElement = (Element) n;  
                String tableName = messagesElement.element("tables").getText();
                String tFields = messagesElement.element("fields").getText();
                tableFields.put(tableName, tFields);
            }
        } catch (Exception e) {
            log4j.error(e.getMessage());
        }       
        return tableFields;
    }

    /**
     * get redis config mysql tables
     */
    public static List<String> getMysqlTables(){
        List<String> tableNameLists = new ArrayList<String>();
        try{
            SAXReader reader = new SAXReader();  
            Document document = null;
            String fileName = resourceBundle.getString("synredis_config");   
            document = reader.read(fileName);
            Element rootElm = document.getRootElement();
            String databaseName = rootElm.element("database").getTextTrim().toString();

            List<Node> list = (List<Node>)document.selectNodes("//synredis/table_data/row");
            for(Node n : list) {  
                Element messagesElement = (Element) n;  
                String tableName = messagesElement.element("tables").getText();
                if(tableName.contains(",") == true){
                    String tableNameSplit[] = tableName.split(",");
                    for(String res : tableNameSplit){
                        tableNameLists.add(res.trim());
                    }
                }else{
                    tableNameLists.add(tableName.trim());
                }
            }
        } catch (Exception e) {
            log4j.error(e.getMessage());
        }
        //去重
        List<String> tableNameListsResult = new ArrayList<String>(new HashSet<String>(tableNameLists));
        return tableNameListsResult;
    }

    /**
     * get data
     */
    public static void getData(){
        String zookeeper_ip = resourceBundle.getString("zookeeper_ip");
        String canal_ip = resourceBundle.getString("canal_ip");
        String canal_destination = resourceBundle.getString("canal_destination");
        String redisConfigDatabaseName = getMysqlDatabaseName();
        CanalConnector connector;
        if (zookeeper_ip == null || zookeeper_ip.equals("") ) { //当zookeeper_ip为空时用单例模式
            String[] canalStrArray = canal_ip.split(":");
            connector = CanalConnectors.newSingleConnector(new InetSocketAddress(canalStrArray[0], 
                                                               Integer.parseInt(canalStrArray[1])), canal_destination, "", "");
        } else {
            connector = CanalConnectors.newClusterConnector(zookeeper_ip, canal_destination, "", "");
        }
        int batchSize = 1024 * 5;
        RmqHandler rmqHandler = new RmqHandler(resourceBundle);
        try{
            connector.connect();
            connector.subscribe(redisConfigDatabaseName + "\\..*");
            connector.rollback();
            while (true) {
                Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据
                long batchId = message.getId();
                int size = message.getEntries().size();
                int checkSize = 1;
                if (batchId == -1 || size == 0) {
                    checkSize = 0;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        log4j.error(e.getMessage());
                    }
                } else {
                    checkSize = getEntry(message.getEntries(), size, rmqHandler);
                }
                if (checkSize <= 0) {
                     //提交确认
                    connector.ack(batchId);
                }else{
                    log4j.error("ack error!");
                }
            }
        }finally {
            RmqHandler.closeConn();
            connector.disconnect(); 
        }
    }

    /**
     * 
     * @param entrys
     */
    public static int getEntry(List<Entry> entrys, int size, RmqHandler rHandler){
        for (Entry entry : entrys) {
            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
                size--;
                continue;
            }
            RowChange rowChage = null;
            try {
                rowChage = RowChange.parseFrom(entry.getStoreValue());
            } catch (Exception e) {
                throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(), e);
            }

            String databaseName = entry.getHeader().getSchemaName();
            String tableName = entry.getHeader().getTableName();
            EventType eventType = rowChage.getEventType();

            //check database name is or not redis config xml
            String redisConfigDatabaseName = getMysqlDatabaseName();
            //check tables name is or not redis config xml
            List<String> redisConfigTables = getMysqlTables();
            if ((databaseName.equals(redisConfigDatabaseName)) && (redisConfigTables.contains(tableName))) {
                Map<String,String> tableConfigFields = new HashMap<String, String>();
                //取消检测字段是否更新条件
                /*
                tableConfigFields = getMysqlTableFields();
                String tableFieldsString = tableConfigFields.get(tableName);
                */

                for (RowData rowData : rowChage.getRowDatasList()) {  

                    Boolean isPublish = false;
                    ObjectToJson result = new ObjectToJson();
                    result.beforeData =  getColumns(rowData.getBeforeColumnsList());
                    result.afterData =  getColumns(rowData.getAfterColumnsList());
                    result.tableName = tableName;
                    result.databaseName = databaseName;
                    result.redisFields = null;
                    result.updatedFields = getUpdatedColumns(rowData.getAfterColumnsList());
                    if (eventType == EventType.DELETE) {
                        result.eventType= "DELETE";
                        isPublish = true;
                    } else if (eventType == EventType.INSERT) {
                        result.eventType= "INSERT";
                        isPublish = true;
                    } else {
                        result.eventType= "UPDATE";
                        isPublish = true;
                        //取消检测字段是否更新条件
                        //isPublish = updateIsPublish(tableFieldsString, result.updatedFields);
                    }
                    String message = new Gson().toJson(result);
                    String channel = databaseName + "." + tableName;
                    if (isPublish == true) {
                        try {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
                            Date date = new java.util.Date();                           
                            String timeStr=sdf.format(date);
                            Boolean redisTodoResut = rHandler.toPublish(channel, message.toString());
                            if (redisTodoResut == true) {
                                System.out.println(timeStr + " databaseName:"+databaseName+" - tableName:"+tableName+" publish ok");
                            }else{
                                System.out.println(timeStr + " : databaseName:"+databaseName+" - tableName:"+tableName+" publish error");
                            }
                        } catch(Exception e) {
                            log4j.error(e.getMessage());
                        }
                    }else{

                    }
                }
            }
            size--;
        }  
        return size;
    }

    private static Boolean updateIsPublish(String redisFields, String updatedFields){
        Boolean isPublish = false;
        String[] redisFieldsStr = redisFields.split(",");
        List<String> redisFieldsList = new ArrayList<String>(Arrays.asList(redisFieldsStr));
        String[] updatedFieldsStr = updatedFields.split(",");
        List<String> updatedFieldsList =  new ArrayList<String>(Arrays.asList(updatedFieldsStr));
        try {
            redisFieldsList.retainAll(updatedFieldsList);
            if(redisFieldsList.size() > 0) {
                isPublish =  true;
            }

        }catch(Exception e) {
            log4j.error(e.getMessage());
        }
        return isPublish;
    }

    /**
     * get updated columns
     * @param columns
     * @return
     */
    private static String getUpdatedColumns(List<Column> columns){
        List<String> updatedColumns = new ArrayList<String>();
        for (Column column : columns) {
            if (column.getUpdated() == true){
                updatedColumns.add(column.getName());
            }
        }
        return StringUtils.join(updatedColumns.toArray(), ',');
    }

    /**
     * 
     * @param columns
     * @return
     */
    private static Map<String, String> getColumns(List<Column> columns){
        Map<String, String> map = new LinkedHashMap<String, String>();      
        for (Column column : columns) {
            map.put(column.getName(), column.getValue());
        }
        return  map;
    }   
}

2015年06月 9日  9:00 Tue PM by josephzeng push

Date: 2015-06-07

Author: josephzeng

Created: 2015-06-11 Thu 00:30

Emacs 24.4.1 (Org mode 8.2.10)

Validate